blob: 21d64df21c7abb426964b2f50377143f705a6120 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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 Murdoch3ef787d2012-04-12 10:51:47 +010038#include "platform.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010039#include "runtime-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040#include "serialize.h"
41#include "string-stream.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010042#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000043
44namespace v8 {
45namespace internal {
46
Steve Blocka7e24c12009-10-30 11:49:00 +000047//
48// Sliding state window. Updates counters to keep track of the last
49// window of kBufferSize states. This is useful to track where we
50// spent our time.
51//
52class SlidingStateWindow {
53 public:
Steve Block44f0eee2011-05-26 01:26:41 +010054 explicit SlidingStateWindow(Isolate* isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000055 ~SlidingStateWindow();
56 void AddState(StateTag state);
57
58 private:
59 static const int kBufferSize = 256;
Steve Block44f0eee2011-05-26 01:26:41 +010060 Counters* counters_;
Steve Blocka7e24c12009-10-30 11:49:00 +000061 int current_index_;
62 bool is_full_;
63 byte buffer_[kBufferSize];
64
65
66 void IncrementStateCounter(StateTag state) {
Steve Block44f0eee2011-05-26 01:26:41 +010067 counters_->state_counters(state)->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +000068 }
69
70
71 void DecrementStateCounter(StateTag state) {
Steve Block44f0eee2011-05-26 01:26:41 +010072 counters_->state_counters(state)->Decrement();
Steve Blocka7e24c12009-10-30 11:49:00 +000073 }
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:
Steve Block44f0eee2011-05-26 01:26:41 +010085 explicit Profiler(Isolate* isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000086 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.
Steve Block44f0eee2011-05-26 01:26:41 +0100116 bool paused() const { return paused_; }
117 void pause() { paused_ = true; }
118 void resume() { paused_ = false; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000119
120 private:
121 // Returns the next index in the cyclic buffer.
122 int Succ(int index) { return (index + 1) % kBufferSize; }
123
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000124 Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 // Cyclic buffer for communicating profiling samples
126 // between the signal handler and the worker thread.
127 static const int kBufferSize = 128;
128 TickSample buffer_[kBufferSize]; // Buffer storage.
129 int head_; // Index to the buffer head.
130 int tail_; // Index to the buffer tail.
131 bool overflow_; // Tell whether a buffer overflow has occurred.
132 Semaphore* buffer_semaphore_; // Sempahore used for buffer synchronization.
133
Steve Blockd0582a62009-12-15 09:54:21 +0000134 // Tells whether profiler is engaged, that is, processing thread is stated.
135 bool engaged_;
136
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 // Tells whether worker thread should continue running.
138 bool running_;
139
140 // Tells whether we are currently recording tick samples.
Steve Block44f0eee2011-05-26 01:26:41 +0100141 bool paused_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000142};
143
Steve Blocka7e24c12009-10-30 11:49:00 +0000144
145//
146// StackTracer implementation
147//
Steve Block44f0eee2011-05-26 01:26:41 +0100148void StackTracer::Trace(Isolate* isolate, TickSample* sample) {
149 ASSERT(isolate->IsInitialized());
150
Ben Murdochb0fe1622011-05-05 13:52:32 +0100151 // Avoid collecting traces while doing GC.
Steve Block6ded16b2010-05-10 14:33:55 +0100152 if (sample->state == GC) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000153
Steve Block44f0eee2011-05-26 01:26:41 +0100154 const Address js_entry_sp =
155 Isolate::js_entry_sp(isolate->thread_local_top());
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 if (js_entry_sp == 0) {
157 // Not executing JS now.
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 return;
159 }
160
Steve Block44f0eee2011-05-26 01:26:41 +0100161 const Address callback = isolate->external_callback();
162 if (callback != NULL) {
163 sample->external_callback = callback;
164 sample->has_external_callback = true;
165 } else {
166 // Sample potential return address value for frameless invocation of
167 // stubs (we'll figure out later, if this value makes sense).
168 sample->tos = Memory::Address_at(sample->sp);
169 sample->has_external_callback = false;
Steve Blockd0582a62009-12-15 09:54:21 +0000170 }
171
Steve Block44f0eee2011-05-26 01:26:41 +0100172 SafeStackTraceFrameIterator it(isolate,
173 sample->fp, sample->sp,
Leon Clarked91b9f72010-01-27 17:25:45 +0000174 sample->sp, js_entry_sp);
Steve Block44f0eee2011-05-26 01:26:41 +0100175 int i = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 while (!it.done() && i < TickSample::kMaxFramesCount) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100177 sample->stack[i++] = it.frame()->pc();
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 it.Advance();
179 }
180 sample->frames_count = i;
181}
182
183
184//
185// Ticker used to provide ticks to the profiler and the sliding state
186// window.
187//
188class Ticker: public Sampler {
189 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +0100190 Ticker(Isolate* isolate, int interval):
Steve Block44f0eee2011-05-26 01:26:41 +0100191 Sampler(isolate, interval),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100192 window_(NULL),
193 profiler_(NULL) {}
Steve Blocka7e24c12009-10-30 11:49:00 +0000194
195 ~Ticker() { if (IsActive()) Stop(); }
196
Ben Murdochf87a2032010-10-22 12:50:53 +0100197 virtual void Tick(TickSample* sample) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 if (profiler_) profiler_->Insert(sample);
199 if (window_) window_->AddState(sample->state);
200 }
201
202 void SetWindow(SlidingStateWindow* window) {
203 window_ = window;
204 if (!IsActive()) Start();
205 }
206
207 void ClearWindow() {
208 window_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100209 if (!profiler_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop();
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 }
211
212 void SetProfiler(Profiler* profiler) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213 ASSERT(profiler_ == NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 profiler_ = profiler;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100215 IncreaseProfilingDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +0000216 if (!FLAG_prof_lazy && !IsActive()) Start();
217 }
218
219 void ClearProfiler() {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100220 DecreaseProfilingDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 profiler_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100222 if (!window_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop();
Steve Blocka7e24c12009-10-30 11:49:00 +0000223 }
224
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800225 protected:
226 virtual void DoSampleStack(TickSample* sample) {
Steve Block44f0eee2011-05-26 01:26:41 +0100227 StackTracer::Trace(isolate(), sample);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800228 }
229
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 private:
231 SlidingStateWindow* window_;
232 Profiler* profiler_;
233};
234
235
236//
237// SlidingStateWindow implementation.
238//
Steve Block44f0eee2011-05-26 01:26:41 +0100239SlidingStateWindow::SlidingStateWindow(Isolate* isolate)
240 : counters_(isolate->counters()), current_index_(0), is_full_(false) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 for (int i = 0; i < kBufferSize; i++) {
242 buffer_[i] = static_cast<byte>(OTHER);
243 }
Steve Block44f0eee2011-05-26 01:26:41 +0100244 isolate->logger()->ticker_->SetWindow(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000245}
246
247
248SlidingStateWindow::~SlidingStateWindow() {
Steve Block44f0eee2011-05-26 01:26:41 +0100249 LOGGER->ticker_->ClearWindow();
Steve Blocka7e24c12009-10-30 11:49:00 +0000250}
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 Block44f0eee2011-05-26 01:26:41 +0100269Profiler::Profiler(Isolate* isolate)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000270 : Thread("v8:Profiler"),
271 isolate_(isolate),
Steve Block9fac8402011-05-12 15:51:54 +0100272 head_(0),
Steve Blockd0582a62009-12-15 09:54:21 +0000273 tail_(0),
274 overflow_(false),
275 buffer_semaphore_(OS::CreateSemaphore(0)),
276 engaged_(false),
Steve Block44f0eee2011-05-26 01:26:41 +0100277 running_(false),
278 paused_(false) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000279}
280
281
282void Profiler::Engage() {
Steve Blockd0582a62009-12-15 09:54:21 +0000283 if (engaged_) return;
284 engaged_ = true;
285
286 // TODO(mnaganov): This is actually "Chromium" mode. Flags need to be revised.
287 // http://code.google.com/p/v8/issues/detail?id=487
288 if (!FLAG_prof_lazy) {
289 OS::LogSharedLibraryAddresses();
290 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000291
292 // Start thread processing the profiler buffer.
293 running_ = true;
294 Start();
295
296 // Register to get ticks.
Steve Block44f0eee2011-05-26 01:26:41 +0100297 LOGGER->ticker_->SetProfiler(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000298
Steve Block44f0eee2011-05-26 01:26:41 +0100299 LOGGER->ProfilerBeginEvent();
Steve Blocka7e24c12009-10-30 11:49:00 +0000300}
301
302
303void Profiler::Disengage() {
Steve Blockd0582a62009-12-15 09:54:21 +0000304 if (!engaged_) return;
305
Steve Blocka7e24c12009-10-30 11:49:00 +0000306 // Stop receiving ticks.
Steve Block44f0eee2011-05-26 01:26:41 +0100307 LOGGER->ticker_->ClearProfiler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000308
309 // Terminate the worker thread by setting running_ to false,
310 // inserting a fake element in the queue and then wait for
311 // the thread to terminate.
312 running_ = false;
313 TickSample sample;
314 // Reset 'paused_' flag, otherwise semaphore may not be signalled.
315 resume();
316 Insert(&sample);
317 Join();
318
Steve Block44f0eee2011-05-26 01:26:41 +0100319 LOG(ISOLATE, UncheckedStringEvent("profiler", "end"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000320}
321
322
323void Profiler::Run() {
324 TickSample sample;
Steve Block8defd9f2010-07-08 12:39:36 +0100325 bool overflow = Remove(&sample);
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 while (running_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000327 LOG(isolate_, TickEvent(&sample, overflow));
Steve Block8defd9f2010-07-08 12:39:36 +0100328 overflow = Remove(&sample);
Steve Blocka7e24c12009-10-30 11:49:00 +0000329 }
330}
331
332
Ben Murdoch257744e2011-11-30 15:57:28 +0000333// Low-level profiling event structures.
334
335struct LowLevelCodeCreateStruct {
336 static const char kTag = 'C';
337
338 int32_t name_size;
339 Address code_address;
340 int32_t code_size;
341};
342
343
344struct LowLevelCodeMoveStruct {
345 static const char kTag = 'M';
346
347 Address from_address;
348 Address to_address;
349};
350
351
352struct LowLevelCodeDeleteStruct {
353 static const char kTag = 'D';
354
355 Address address;
356};
357
358
359struct LowLevelSnapshotPositionStruct {
360 static const char kTag = 'P';
361
362 Address address;
363 int32_t position;
364};
365
366
367static const char kCodeMovingGCTag = 'G';
368
369
Steve Blocka7e24c12009-10-30 11:49:00 +0000370//
371// Logger class implementation.
372//
Steve Block44f0eee2011-05-26 01:26:41 +0100373
Ben Murdoch257744e2011-11-30 15:57:28 +0000374class Logger::NameMap {
375 public:
376 NameMap() : impl_(&PointerEquals) {}
377
378 ~NameMap() {
379 for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) {
380 DeleteArray(static_cast<const char*>(p->value));
381 }
382 }
383
384 void Insert(Address code_address, const char* name, int name_size) {
385 HashMap::Entry* entry = FindOrCreateEntry(code_address);
386 if (entry->value == NULL) {
387 entry->value = CopyName(name, name_size);
388 }
389 }
390
391 const char* Lookup(Address code_address) {
392 HashMap::Entry* entry = FindEntry(code_address);
393 return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
394 }
395
396 void Remove(Address code_address) {
397 HashMap::Entry* entry = FindEntry(code_address);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000398 if (entry != NULL) {
399 DeleteArray(static_cast<char*>(entry->value));
400 RemoveEntry(entry);
401 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000402 }
403
404 void Move(Address from, Address to) {
405 if (from == to) return;
406 HashMap::Entry* from_entry = FindEntry(from);
407 ASSERT(from_entry != NULL);
408 void* value = from_entry->value;
409 RemoveEntry(from_entry);
410 HashMap::Entry* to_entry = FindOrCreateEntry(to);
411 ASSERT(to_entry->value == NULL);
412 to_entry->value = value;
413 }
414
415 private:
416 static bool PointerEquals(void* lhs, void* rhs) {
417 return lhs == rhs;
418 }
419
420 static char* CopyName(const char* name, int name_size) {
421 char* result = NewArray<char>(name_size + 1);
422 for (int i = 0; i < name_size; ++i) {
423 char c = name[i];
424 if (c == '\0') c = ' ';
425 result[i] = c;
426 }
427 result[name_size] = '\0';
428 return result;
429 }
430
431 HashMap::Entry* FindOrCreateEntry(Address code_address) {
432 return impl_.Lookup(code_address, ComputePointerHash(code_address), true);
433 }
434
435 HashMap::Entry* FindEntry(Address code_address) {
436 return impl_.Lookup(code_address, ComputePointerHash(code_address), false);
437 }
438
439 void RemoveEntry(HashMap::Entry* entry) {
440 impl_.Remove(entry->key, entry->hash);
441 }
442
443 HashMap impl_;
444
445 DISALLOW_COPY_AND_ASSIGN(NameMap);
446};
447
448
449class Logger::NameBuffer {
450 public:
451 NameBuffer() { Reset(); }
452
453 void Reset() {
454 utf8_pos_ = 0;
455 }
456
457 void AppendString(String* str) {
458 if (str == NULL) return;
459 if (str->HasOnlyAsciiChars()) {
460 int utf8_length = Min(str->length(), kUtf8BufferSize - utf8_pos_);
461 String::WriteToFlat(str, utf8_buffer_ + utf8_pos_, 0, utf8_length);
462 utf8_pos_ += utf8_length;
463 return;
464 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100465 int uc16_length = Min(str->length(), kUtf16BufferSize);
466 String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
467 int previous = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdoch257744e2011-11-30 15:57:28 +0000468 for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100469 uc16 c = utf16_buffer[i];
Ben Murdoch257744e2011-11-30 15:57:28 +0000470 if (c <= String::kMaxAsciiCharCodeU) {
471 utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
472 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100473 int char_length = unibrow::Utf8::Length(c, previous);
Ben Murdoch257744e2011-11-30 15:57:28 +0000474 if (utf8_pos_ + char_length > kUtf8BufferSize) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100475 unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
Ben Murdoch257744e2011-11-30 15:57:28 +0000476 utf8_pos_ += char_length;
477 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100478 previous = c;
Ben Murdoch257744e2011-11-30 15:57:28 +0000479 }
480 }
481
482 void AppendBytes(const char* bytes, int size) {
483 size = Min(size, kUtf8BufferSize - utf8_pos_);
484 memcpy(utf8_buffer_ + utf8_pos_, bytes, size);
485 utf8_pos_ += size;
486 }
487
488 void AppendBytes(const char* bytes) {
489 AppendBytes(bytes, StrLength(bytes));
490 }
491
492 void AppendByte(char c) {
493 if (utf8_pos_ >= kUtf8BufferSize) return;
494 utf8_buffer_[utf8_pos_++] = c;
495 }
496
497 void AppendInt(int n) {
498 Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
499 int size = OS::SNPrintF(buffer, "%d", n);
500 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
501 utf8_pos_ += size;
502 }
503 }
504
505 const char* get() { return utf8_buffer_; }
506 int size() const { return utf8_pos_; }
507
508 private:
509 static const int kUtf8BufferSize = 512;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100510 static const int kUtf16BufferSize = 128;
Ben Murdoch257744e2011-11-30 15:57:28 +0000511
512 int utf8_pos_;
513 char utf8_buffer_[kUtf8BufferSize];
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100514 uc16 utf16_buffer[kUtf16BufferSize];
Ben Murdoch257744e2011-11-30 15:57:28 +0000515};
516
517
Steve Block44f0eee2011-05-26 01:26:41 +0100518Logger::Logger()
519 : ticker_(NULL),
520 profiler_(NULL),
521 sliding_state_window_(NULL),
522 log_events_(NULL),
523 logging_nesting_(0),
524 cpu_profiler_nesting_(0),
Steve Block44f0eee2011-05-26 01:26:41 +0100525 log_(new Log(this)),
Ben Murdoch257744e2011-11-30 15:57:28 +0000526 name_buffer_(new NameBuffer),
527 address_to_name_map_(NULL),
Steve Block44f0eee2011-05-26 01:26:41 +0100528 is_initialized_(false),
529 last_address_(NULL),
530 prev_sp_(NULL),
531 prev_function_(NULL),
532 prev_to_(NULL),
533 prev_code_(NULL) {
534}
535
Ben Murdoch257744e2011-11-30 15:57:28 +0000536
Steve Block44f0eee2011-05-26 01:26:41 +0100537Logger::~Logger() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000538 delete address_to_name_map_;
539 delete name_buffer_;
Steve Block44f0eee2011-05-26 01:26:41 +0100540 delete log_;
541}
Steve Blocka7e24c12009-10-30 11:49:00 +0000542
Ben Murdoch257744e2011-11-30 15:57:28 +0000543
Ben Murdochb0fe1622011-05-05 13:52:32 +0100544#define DECLARE_EVENT(ignore1, name) name,
Steve Block44f0eee2011-05-26 01:26:41 +0100545static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100546 LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
Steve Blocka7e24c12009-10-30 11:49:00 +0000547};
Ben Murdochb0fe1622011-05-05 13:52:32 +0100548#undef DECLARE_EVENT
Steve Blocka7e24c12009-10-30 11:49:00 +0000549
550
551void Logger::ProfilerBeginEvent() {
Steve Block44f0eee2011-05-26 01:26:41 +0100552 if (!log_->IsEnabled()) return;
553 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 msg.WriteToLogFile();
556}
557
Steve Blocka7e24c12009-10-30 11:49:00 +0000558
Steve Blocka7e24c12009-10-30 11:49:00 +0000559void Logger::StringEvent(const char* name, const char* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 if (FLAG_log) UncheckedStringEvent(name, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000561}
562
563
Steve Blocka7e24c12009-10-30 11:49:00 +0000564void Logger::UncheckedStringEvent(const char* name, const char* value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100565 if (!log_->IsEnabled()) return;
566 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000567 msg.Append("%s,\"%s\"\n", name, value);
568 msg.WriteToLogFile();
569}
Steve Blocka7e24c12009-10-30 11:49:00 +0000570
571
572void Logger::IntEvent(const char* name, int value) {
Steve Block6ded16b2010-05-10 14:33:55 +0100573 if (FLAG_log) UncheckedIntEvent(name, value);
Steve Block6ded16b2010-05-10 14:33:55 +0100574}
575
576
Ben Murdochf87a2032010-10-22 12:50:53 +0100577void Logger::IntPtrTEvent(const char* name, intptr_t value) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100578 if (FLAG_log) UncheckedIntPtrTEvent(name, value);
Ben Murdochf87a2032010-10-22 12:50:53 +0100579}
580
581
Steve Block6ded16b2010-05-10 14:33:55 +0100582void Logger::UncheckedIntEvent(const char* name, int value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100583 if (!log_->IsEnabled()) return;
584 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000585 msg.Append("%s,%d\n", name, value);
586 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000587}
588
589
Ben Murdochf87a2032010-10-22 12:50:53 +0100590void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
Steve Block44f0eee2011-05-26 01:26:41 +0100591 if (!log_->IsEnabled()) return;
592 LogMessageBuilder msg(this);
Ben Murdochf87a2032010-10-22 12:50:53 +0100593 msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
594 msg.WriteToLogFile();
595}
Ben Murdochf87a2032010-10-22 12:50:53 +0100596
597
Steve Blocka7e24c12009-10-30 11:49:00 +0000598void Logger::HandleEvent(const char* name, Object** location) {
Steve Block44f0eee2011-05-26 01:26:41 +0100599 if (!log_->IsEnabled() || !FLAG_log_handles) return;
600 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
602 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000603}
604
605
Steve Blocka7e24c12009-10-30 11:49:00 +0000606// ApiEvent is private so all the calls come from the Logger class. It is the
607// caller's responsibility to ensure that log is enabled and that
608// FLAG_log_api is true.
609void Logger::ApiEvent(const char* format, ...) {
Steve Block44f0eee2011-05-26 01:26:41 +0100610 ASSERT(log_->IsEnabled() && FLAG_log_api);
611 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000612 va_list ap;
613 va_start(ap, format);
614 msg.AppendVA(format, ap);
615 va_end(ap);
616 msg.WriteToLogFile();
617}
Steve Blocka7e24c12009-10-30 11:49:00 +0000618
619
620void Logger::ApiNamedSecurityCheck(Object* key) {
Steve Block44f0eee2011-05-26 01:26:41 +0100621 if (!log_->IsEnabled() || !FLAG_log_api) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 if (key->IsString()) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000623 SmartArrayPointer<char> str =
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
625 ApiEvent("api,check-security,\"%s\"\n", *str);
626 } else if (key->IsUndefined()) {
627 ApiEvent("api,check-security,undefined\n");
628 } else {
629 ApiEvent("api,check-security,['no-name']\n");
630 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000631}
632
633
634void Logger::SharedLibraryEvent(const char* library_path,
635 uintptr_t start,
636 uintptr_t end) {
Steve Block44f0eee2011-05-26 01:26:41 +0100637 if (!log_->IsEnabled() || !FLAG_prof) return;
638 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000639 msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
640 library_path,
641 start,
642 end);
643 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000644}
645
646
647void Logger::SharedLibraryEvent(const wchar_t* library_path,
648 uintptr_t start,
649 uintptr_t end) {
Steve Block44f0eee2011-05-26 01:26:41 +0100650 if (!log_->IsEnabled() || !FLAG_prof) return;
651 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
653 library_path,
654 start,
655 end);
656 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000657}
658
659
Steve Blocka7e24c12009-10-30 11:49:00 +0000660void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
661 // Prints "/" + re.source + "/" +
662 // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
Steve Block44f0eee2011-05-26 01:26:41 +0100663 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000664
665 Handle<Object> source = GetProperty(regexp, "source");
666 if (!source->IsString()) {
667 msg.Append("no source");
668 return;
669 }
670
671 switch (regexp->TypeTag()) {
672 case JSRegExp::ATOM:
673 msg.Append('a');
674 break;
675 default:
676 break;
677 }
678 msg.Append('/');
679 msg.AppendDetailed(*Handle<String>::cast(source), false);
680 msg.Append('/');
681
682 // global flag
683 Handle<Object> global = GetProperty(regexp, "global");
684 if (global->IsTrue()) {
685 msg.Append('g');
686 }
687 // ignorecase flag
688 Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
689 if (ignorecase->IsTrue()) {
690 msg.Append('i');
691 }
692 // multiline flag
693 Handle<Object> multiline = GetProperty(regexp, "multiline");
694 if (multiline->IsTrue()) {
695 msg.Append('m');
696 }
697
698 msg.WriteToLogFile();
699}
Steve Blocka7e24c12009-10-30 11:49:00 +0000700
701
702void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
Steve Block44f0eee2011-05-26 01:26:41 +0100703 if (!log_->IsEnabled() || !FLAG_log_regexp) return;
704 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000705 msg.Append("regexp-compile,");
706 LogRegExpSource(regexp);
707 msg.Append(in_cache ? ",hit\n" : ",miss\n");
708 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000709}
710
711
712void Logger::LogRuntime(Vector<const char> format, JSArray* args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100713 if (!log_->IsEnabled() || !FLAG_log_runtime) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000714 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +0100715 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000716 for (int i = 0; i < format.length(); i++) {
717 char c = format[i];
718 if (c == '%' && i <= format.length() - 2) {
719 i++;
720 ASSERT('0' <= format[i] && format[i] <= '9');
John Reck59135872010-11-02 12:39:01 -0700721 MaybeObject* maybe = args->GetElement(format[i] - '0');
722 Object* obj;
723 if (!maybe->ToObject(&obj)) {
724 msg.Append("<exception>");
725 continue;
726 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000727 i++;
728 switch (format[i]) {
729 case 's':
730 msg.AppendDetailed(String::cast(obj), false);
731 break;
732 case 'S':
733 msg.AppendDetailed(String::cast(obj), true);
734 break;
735 case 'r':
736 Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
737 break;
738 case 'x':
739 msg.Append("0x%x", Smi::cast(obj)->value());
740 break;
741 case 'i':
742 msg.Append("%i", Smi::cast(obj)->value());
743 break;
744 default:
745 UNREACHABLE();
746 }
747 } else {
748 msg.Append(c);
749 }
750 }
751 msg.Append('\n');
752 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000753}
754
755
756void Logger::ApiIndexedSecurityCheck(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100757 if (!log_->IsEnabled() || !FLAG_log_api) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000758 ApiEvent("api,check-security,%u\n", index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000759}
760
761
762void Logger::ApiNamedPropertyAccess(const char* tag,
763 JSObject* holder,
764 Object* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 ASSERT(name->IsString());
Steve Block44f0eee2011-05-26 01:26:41 +0100766 if (!log_->IsEnabled() || !FLAG_log_api) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 String* class_name_obj = holder->class_name();
Ben Murdoch589d6972011-11-30 16:04:58 +0000768 SmartArrayPointer<char> class_name =
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Ben Murdoch589d6972011-11-30 16:04:58 +0000770 SmartArrayPointer<char> property_name =
Steve Blocka7e24c12009-10-30 11:49:00 +0000771 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Steve Block44f0eee2011-05-26 01:26:41 +0100772 ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000773}
774
775void Logger::ApiIndexedPropertyAccess(const char* tag,
776 JSObject* holder,
777 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100778 if (!log_->IsEnabled() || !FLAG_log_api) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 String* class_name_obj = holder->class_name();
Ben Murdoch589d6972011-11-30 16:04:58 +0000780 SmartArrayPointer<char> class_name =
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Steve Block44f0eee2011-05-26 01:26:41 +0100782 ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000783}
784
785void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
Steve Block44f0eee2011-05-26 01:26:41 +0100786 if (!log_->IsEnabled() || !FLAG_log_api) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000787 String* class_name_obj = object->class_name();
Ben Murdoch589d6972011-11-30 16:04:58 +0000788 SmartArrayPointer<char> class_name =
Steve Blocka7e24c12009-10-30 11:49:00 +0000789 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Steve Block44f0eee2011-05-26 01:26:41 +0100790 ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000791}
792
793
794void Logger::ApiEntryCall(const char* name) {
Steve Block44f0eee2011-05-26 01:26:41 +0100795 if (!log_->IsEnabled() || !FLAG_log_api) return;
796 ApiEvent("api,%s\n", name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000797}
798
799
800void Logger::NewEvent(const char* name, void* object, size_t size) {
Steve Block44f0eee2011-05-26 01:26:41 +0100801 if (!log_->IsEnabled() || !FLAG_log) return;
802 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
804 static_cast<unsigned int>(size));
805 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000806}
807
808
809void Logger::DeleteEvent(const char* name, void* object) {
Steve Block44f0eee2011-05-26 01:26:41 +0100810 if (!log_->IsEnabled() || !FLAG_log) return;
811 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000812 msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
813 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000814}
815
816
Steve Block44f0eee2011-05-26 01:26:41 +0100817void Logger::NewEventStatic(const char* name, void* object, size_t size) {
818 LOGGER->NewEvent(name, object, size);
819}
820
821
822void Logger::DeleteEventStatic(const char* name, void* object) {
823 LOGGER->DeleteEvent(name, object);
824}
825
Steve Blockd0582a62009-12-15 09:54:21 +0000826void Logger::CallbackEventInternal(const char* prefix, const char* name,
827 Address entry_point) {
Steve Block44f0eee2011-05-26 01:26:41 +0100828 if (!log_->IsEnabled() || !FLAG_log_code) return;
829 LogMessageBuilder msg(this);
Steve Blockd0582a62009-12-15 09:54:21 +0000830 msg.Append("%s,%s,",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100831 kLogEventsNames[CODE_CREATION_EVENT],
832 kLogEventsNames[CALLBACK_TAG]);
Steve Blockd0582a62009-12-15 09:54:21 +0000833 msg.AppendAddress(entry_point);
834 msg.Append(",1,\"%s%s\"", prefix, name);
Steve Blockd0582a62009-12-15 09:54:21 +0000835 msg.Append('\n');
836 msg.WriteToLogFile();
837}
Steve Blockd0582a62009-12-15 09:54:21 +0000838
839
840void Logger::CallbackEvent(String* name, Address entry_point) {
Steve Block44f0eee2011-05-26 01:26:41 +0100841 if (!log_->IsEnabled() || !FLAG_log_code) return;
Ben Murdoch589d6972011-11-30 16:04:58 +0000842 SmartArrayPointer<char> str =
Steve Blockd0582a62009-12-15 09:54:21 +0000843 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
844 CallbackEventInternal("", *str, entry_point);
Steve Blockd0582a62009-12-15 09:54:21 +0000845}
846
847
848void Logger::GetterCallbackEvent(String* name, Address entry_point) {
Steve Block44f0eee2011-05-26 01:26:41 +0100849 if (!log_->IsEnabled() || !FLAG_log_code) return;
Ben Murdoch589d6972011-11-30 16:04:58 +0000850 SmartArrayPointer<char> str =
Steve Blockd0582a62009-12-15 09:54:21 +0000851 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
852 CallbackEventInternal("get ", *str, entry_point);
Steve Blockd0582a62009-12-15 09:54:21 +0000853}
854
855
856void Logger::SetterCallbackEvent(String* name, Address entry_point) {
Steve Block44f0eee2011-05-26 01:26:41 +0100857 if (!log_->IsEnabled() || !FLAG_log_code) return;
Ben Murdoch589d6972011-11-30 16:04:58 +0000858 SmartArrayPointer<char> str =
Steve Blockd0582a62009-12-15 09:54:21 +0000859 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
860 CallbackEventInternal("set ", *str, entry_point);
Steve Blockd0582a62009-12-15 09:54:21 +0000861}
862
863
Steve Blocka7e24c12009-10-30 11:49:00 +0000864void Logger::CodeCreateEvent(LogEventsAndTags tag,
865 Code* code,
866 const char* comment) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000867 if (!log_->IsEnabled()) return;
868 if (FLAG_ll_prof || Serializer::enabled()) {
869 name_buffer_->Reset();
870 name_buffer_->AppendBytes(kLogEventsNames[tag]);
871 name_buffer_->AppendByte(':');
872 name_buffer_->AppendBytes(comment);
873 }
874 if (FLAG_ll_prof) {
875 LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
876 }
877 if (Serializer::enabled()) {
878 RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
879 }
880 if (!FLAG_log_code) return;
Steve Block44f0eee2011-05-26 01:26:41 +0100881 LogMessageBuilder msg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100882 msg.Append("%s,%s,",
883 kLogEventsNames[CODE_CREATION_EVENT],
884 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000885 msg.AppendAddress(code->address());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100886 msg.Append(",%d,\"", code->ExecutableSize());
Steve Blocka7e24c12009-10-30 11:49:00 +0000887 for (const char* p = comment; *p != '\0'; p++) {
888 if (*p == '"') {
889 msg.Append('\\');
890 }
891 msg.Append(*p);
892 }
893 msg.Append('"');
Steve Blocka7e24c12009-10-30 11:49:00 +0000894 msg.Append('\n');
895 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000896}
897
898
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100899void Logger::CodeCreateEvent(LogEventsAndTags tag,
900 Code* code,
901 String* name) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000902 if (!log_->IsEnabled()) return;
903 if (FLAG_ll_prof || Serializer::enabled()) {
904 name_buffer_->Reset();
905 name_buffer_->AppendBytes(kLogEventsNames[tag]);
906 name_buffer_->AppendByte(':');
907 name_buffer_->AppendString(name);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100908 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000909 if (FLAG_ll_prof) {
910 LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
911 }
912 if (Serializer::enabled()) {
913 RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
914 }
915 if (!FLAG_log_code) return;
916 LogMessageBuilder msg(this);
917 msg.Append("%s,%s,",
918 kLogEventsNames[CODE_CREATION_EVENT],
919 kLogEventsNames[tag]);
920 msg.AppendAddress(code->address());
921 msg.Append(",%d,\"", code->ExecutableSize());
922 msg.AppendDetailed(name, false);
923 msg.Append('"');
924 msg.Append('\n');
925 msg.WriteToLogFile();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100926}
927
928
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100929// ComputeMarker must only be used when SharedFunctionInfo is known.
930static const char* ComputeMarker(Code* code) {
931 switch (code->kind()) {
932 case Code::FUNCTION: return code->optimizable() ? "~" : "";
933 case Code::OPTIMIZED_FUNCTION: return "*";
934 default: return "";
935 }
936}
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100937
938
939void Logger::CodeCreateEvent(LogEventsAndTags tag,
940 Code* code,
941 SharedFunctionInfo* shared,
942 String* name) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000943 if (!log_->IsEnabled()) return;
944 if (FLAG_ll_prof || Serializer::enabled()) {
945 name_buffer_->Reset();
946 name_buffer_->AppendBytes(kLogEventsNames[tag]);
947 name_buffer_->AppendByte(':');
948 name_buffer_->AppendBytes(ComputeMarker(code));
949 name_buffer_->AppendString(name);
950 }
951 if (FLAG_ll_prof) {
952 LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
953 }
954 if (Serializer::enabled()) {
955 RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
956 }
957 if (!FLAG_log_code) return;
Steve Block44f0eee2011-05-26 01:26:41 +0100958 if (code == Isolate::Current()->builtins()->builtin(
959 Builtins::kLazyCompile))
960 return;
961
962 LogMessageBuilder msg(this);
Ben Murdoch589d6972011-11-30 16:04:58 +0000963 SmartArrayPointer<char> str =
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100965 msg.Append("%s,%s,",
966 kLogEventsNames[CODE_CREATION_EVENT],
967 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 msg.AppendAddress(code->address());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100969 msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
970 msg.AppendAddress(shared->address());
971 msg.Append(",%s", ComputeMarker(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000972 msg.Append('\n');
973 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000974}
975
976
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100977// Although, it is possible to extract source and line from
978// the SharedFunctionInfo object, we left it to caller
979// to leave logging functions free from heap allocations.
Steve Blocka7e24c12009-10-30 11:49:00 +0000980void Logger::CodeCreateEvent(LogEventsAndTags tag,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100981 Code* code,
982 SharedFunctionInfo* shared,
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 String* source, int line) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000984 if (!log_->IsEnabled()) return;
985 if (FLAG_ll_prof || Serializer::enabled()) {
986 name_buffer_->Reset();
987 name_buffer_->AppendBytes(kLogEventsNames[tag]);
988 name_buffer_->AppendByte(':');
989 name_buffer_->AppendBytes(ComputeMarker(code));
990 name_buffer_->AppendString(shared->DebugName());
991 name_buffer_->AppendByte(' ');
992 name_buffer_->AppendString(source);
993 name_buffer_->AppendByte(':');
994 name_buffer_->AppendInt(line);
995 }
996 if (FLAG_ll_prof) {
997 LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
998 }
999 if (Serializer::enabled()) {
1000 RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
1001 }
1002 if (!FLAG_log_code) return;
Steve Block44f0eee2011-05-26 01:26:41 +01001003 LogMessageBuilder msg(this);
Ben Murdoch589d6972011-11-30 16:04:58 +00001004 SmartArrayPointer<char> name =
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001005 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Ben Murdoch589d6972011-11-30 16:04:58 +00001006 SmartArrayPointer<char> sourcestr =
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001008 msg.Append("%s,%s,",
1009 kLogEventsNames[CODE_CREATION_EVENT],
1010 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001011 msg.AppendAddress(code->address());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001012 msg.Append(",%d,\"%s %s:%d\",",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001013 code->ExecutableSize(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001014 *name,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001015 *sourcestr,
1016 line);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001017 msg.AppendAddress(shared->address());
1018 msg.Append(",%s", ComputeMarker(code));
Steve Blocka7e24c12009-10-30 11:49:00 +00001019 msg.Append('\n');
1020 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001021}
1022
1023
1024void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001025 if (!log_->IsEnabled()) return;
1026 if (FLAG_ll_prof || Serializer::enabled()) {
1027 name_buffer_->Reset();
1028 name_buffer_->AppendBytes(kLogEventsNames[tag]);
1029 name_buffer_->AppendByte(':');
1030 name_buffer_->AppendInt(args_count);
1031 }
1032 if (FLAG_ll_prof) {
1033 LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
1034 }
1035 if (Serializer::enabled()) {
1036 RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
1037 }
1038 if (!FLAG_log_code) return;
Steve Block44f0eee2011-05-26 01:26:41 +01001039 LogMessageBuilder msg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001040 msg.Append("%s,%s,",
1041 kLogEventsNames[CODE_CREATION_EVENT],
1042 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001043 msg.AppendAddress(code->address());
1044 msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00001045 msg.Append('\n');
1046 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001047}
1048
1049
Ben Murdochf87a2032010-10-22 12:50:53 +01001050void Logger::CodeMovingGCEvent() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001051 if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1052 LowLevelLogWriteBytes(&kCodeMovingGCTag, sizeof(kCodeMovingGCTag));
Ben Murdochf87a2032010-10-22 12:50:53 +01001053 OS::SignalCodeMovingGC();
Ben Murdochf87a2032010-10-22 12:50:53 +01001054}
1055
1056
Steve Blocka7e24c12009-10-30 11:49:00 +00001057void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001058 if (!log_->IsEnabled()) return;
1059 if (FLAG_ll_prof || Serializer::enabled()) {
1060 name_buffer_->Reset();
1061 name_buffer_->AppendBytes(kLogEventsNames[REG_EXP_TAG]);
1062 name_buffer_->AppendByte(':');
1063 name_buffer_->AppendString(source);
1064 }
1065 if (FLAG_ll_prof) {
1066 LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
1067 }
1068 if (Serializer::enabled()) {
1069 RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
1070 }
1071 if (!FLAG_log_code) return;
Steve Block44f0eee2011-05-26 01:26:41 +01001072 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001073 msg.Append("%s,%s,",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001074 kLogEventsNames[CODE_CREATION_EVENT],
1075 kLogEventsNames[REG_EXP_TAG]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001076 msg.AppendAddress(code->address());
1077 msg.Append(",%d,\"", code->ExecutableSize());
1078 msg.AppendDetailed(source, false);
1079 msg.Append('\"');
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 msg.Append('\n');
1081 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001082}
1083
1084
1085void Logger::CodeMoveEvent(Address from, Address to) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001086 if (!log_->IsEnabled()) return;
1087 if (FLAG_ll_prof) LowLevelCodeMoveEvent(from, to);
1088 if (Serializer::enabled() && address_to_name_map_ != NULL) {
1089 address_to_name_map_->Move(from, to);
1090 }
Leon Clarked91b9f72010-01-27 17:25:45 +00001091 MoveEventInternal(CODE_MOVE_EVENT, from, to);
Steve Blocka7e24c12009-10-30 11:49:00 +00001092}
1093
1094
1095void Logger::CodeDeleteEvent(Address from) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001096 if (!log_->IsEnabled()) return;
1097 if (FLAG_ll_prof) LowLevelCodeDeleteEvent(from);
1098 if (Serializer::enabled() && address_to_name_map_ != NULL) {
1099 address_to_name_map_->Remove(from);
1100 }
Leon Clarked91b9f72010-01-27 17:25:45 +00001101 DeleteEventInternal(CODE_DELETE_EVENT, from);
Steve Blocka7e24c12009-10-30 11:49:00 +00001102}
1103
1104
Leon Clarkee46be812010-01-19 14:06:41 +00001105void Logger::SnapshotPositionEvent(Address addr, int pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001106 if (!log_->IsEnabled()) return;
1107 if (FLAG_ll_prof) LowLevelSnapshotPositionEvent(addr, pos);
1108 if (Serializer::enabled() && address_to_name_map_ != NULL) {
1109 const char* code_name = address_to_name_map_->Lookup(addr);
1110 if (code_name == NULL) return; // Not a code object.
1111 LogMessageBuilder msg(this);
1112 msg.Append("%s,%d,\"", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1113 for (const char* p = code_name; *p != '\0'; ++p) {
1114 if (*p == '"') msg.Append('\\');
1115 msg.Append(*p);
1116 }
1117 msg.Append("\"\n");
1118 msg.WriteToLogFile();
1119 }
1120 if (!FLAG_log_snapshot_positions) return;
Steve Block44f0eee2011-05-26 01:26:41 +01001121 LogMessageBuilder msg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001122 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
Leon Clarkee46be812010-01-19 14:06:41 +00001123 msg.AppendAddress(addr);
1124 msg.Append(",%d", pos);
Leon Clarkee46be812010-01-19 14:06:41 +00001125 msg.Append('\n');
1126 msg.WriteToLogFile();
Leon Clarkee46be812010-01-19 14:06:41 +00001127}
1128
1129
Steve Block44f0eee2011-05-26 01:26:41 +01001130void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
Steve Block44f0eee2011-05-26 01:26:41 +01001131 MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
Leon Clarked91b9f72010-01-27 17:25:45 +00001132}
1133
1134
Leon Clarked91b9f72010-01-27 17:25:45 +00001135void Logger::MoveEventInternal(LogEventsAndTags event,
1136 Address from,
1137 Address to) {
Steve Block44f0eee2011-05-26 01:26:41 +01001138 if (!log_->IsEnabled() || !FLAG_log_code) return;
1139 LogMessageBuilder msg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001140 msg.Append("%s,", kLogEventsNames[event]);
Leon Clarked91b9f72010-01-27 17:25:45 +00001141 msg.AppendAddress(from);
1142 msg.Append(',');
Ben Murdochb0fe1622011-05-05 13:52:32 +01001143 msg.AppendAddress(to);
Leon Clarked91b9f72010-01-27 17:25:45 +00001144 msg.Append('\n');
1145 msg.WriteToLogFile();
1146}
Leon Clarked91b9f72010-01-27 17:25:45 +00001147
1148
Leon Clarked91b9f72010-01-27 17:25:45 +00001149void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) {
Steve Block44f0eee2011-05-26 01:26:41 +01001150 if (!log_->IsEnabled() || !FLAG_log_code) return;
1151 LogMessageBuilder msg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001152 msg.Append("%s,", kLogEventsNames[event]);
Leon Clarked91b9f72010-01-27 17:25:45 +00001153 msg.AppendAddress(from);
Leon Clarked91b9f72010-01-27 17:25:45 +00001154 msg.Append('\n');
1155 msg.WriteToLogFile();
1156}
Leon Clarked91b9f72010-01-27 17:25:45 +00001157
1158
Steve Blocka7e24c12009-10-30 11:49:00 +00001159void Logger::ResourceEvent(const char* name, const char* tag) {
Steve Block44f0eee2011-05-26 01:26:41 +01001160 if (!log_->IsEnabled() || !FLAG_log) return;
1161 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001162 msg.Append("%s,%s,", name, tag);
1163
1164 uint32_t sec, usec;
1165 if (OS::GetUserTime(&sec, &usec) != -1) {
1166 msg.Append("%d,%d,", sec, usec);
1167 }
1168 msg.Append("%.0f", OS::TimeCurrentMillis());
1169
1170 msg.Append('\n');
1171 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001172}
1173
1174
1175void Logger::SuspectReadEvent(String* name, Object* obj) {
Steve Block44f0eee2011-05-26 01:26:41 +01001176 if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1177 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 String* class_name = obj->IsJSObject()
1179 ? JSObject::cast(obj)->class_name()
Steve Block44f0eee2011-05-26 01:26:41 +01001180 : HEAP->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001181 msg.Append("suspect-read,");
1182 msg.Append(class_name);
1183 msg.Append(',');
1184 msg.Append('"');
1185 msg.Append(name);
1186 msg.Append('"');
1187 msg.Append('\n');
1188 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001189}
1190
1191
1192void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01001193 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1194 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 // Using non-relative system time in order to be able to synchronize with
1196 // external memory profiling events (e.g. DOM memory size).
1197 msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
1198 space, kind, OS::TimeCurrentMillis());
1199 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001200}
1201
1202
1203void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01001204 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1205 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
1207 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001208}
1209
1210
1211void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
Steve Block44f0eee2011-05-26 01:26:41 +01001212 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1213 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
1215 msg.WriteToLogFile();
Steve Block3ce2e202009-11-05 08:53:23 +00001216}
1217
1218
Steve Blocka7e24c12009-10-30 11:49:00 +00001219void Logger::DebugTag(const char* call_site_tag) {
Steve Block44f0eee2011-05-26 01:26:41 +01001220 if (!log_->IsEnabled() || !FLAG_log) return;
1221 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001222 msg.Append("debug-tag,%s\n", call_site_tag);
1223 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001224}
1225
1226
1227void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
Steve Block44f0eee2011-05-26 01:26:41 +01001228 if (!log_->IsEnabled() || !FLAG_log) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001229 StringBuilder s(parameter.length() + 1);
1230 for (int i = 0; i < parameter.length(); ++i) {
1231 s.AddCharacter(static_cast<char>(parameter[i]));
1232 }
1233 char* parameter_string = s.Finalize();
Steve Block44f0eee2011-05-26 01:26:41 +01001234 LogMessageBuilder msg(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001235 msg.Append("debug-queue-event,%s,%15.3f,%s\n",
1236 event_type,
1237 OS::TimeCurrentMillis(),
1238 parameter_string);
1239 DeleteArray(parameter_string);
1240 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +00001241}
1242
1243
Steve Blocka7e24c12009-10-30 11:49:00 +00001244void Logger::TickEvent(TickSample* sample, bool overflow) {
Steve Block44f0eee2011-05-26 01:26:41 +01001245 if (!log_->IsEnabled() || !FLAG_prof) return;
1246 LogMessageBuilder msg(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001247 msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1248 msg.AppendAddress(sample->pc);
Steve Blocka7e24c12009-10-30 11:49:00 +00001249 msg.Append(',');
Ben Murdochb0fe1622011-05-05 13:52:32 +01001250 msg.AppendAddress(sample->sp);
Steve Block44f0eee2011-05-26 01:26:41 +01001251 if (sample->has_external_callback) {
1252 msg.Append(",1,");
1253 msg.AppendAddress(sample->external_callback);
1254 } else {
1255 msg.Append(",0,");
1256 msg.AppendAddress(sample->tos);
1257 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001258 msg.Append(",%d", static_cast<int>(sample->state));
1259 if (overflow) {
1260 msg.Append(",overflow");
1261 }
1262 for (int i = 0; i < sample->frames_count; ++i) {
1263 msg.Append(',');
Ben Murdochb0fe1622011-05-05 13:52:32 +01001264 msg.AppendAddress(sample->stack[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 }
1266 msg.Append('\n');
1267 msg.WriteToLogFile();
1268}
1269
1270
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001271bool Logger::IsProfilerPaused() {
1272 return profiler_ == NULL || profiler_->paused();
Steve Blocka7e24c12009-10-30 11:49:00 +00001273}
1274
1275
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001276void Logger::PauseProfiler() {
Steve Block44f0eee2011-05-26 01:26:41 +01001277 if (!log_->IsEnabled()) return;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 if (profiler_ != NULL) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001279 // It is OK to have negative nesting.
1280 if (--cpu_profiler_nesting_ == 0) {
1281 profiler_->pause();
1282 if (FLAG_prof_lazy) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001283 if (!FLAG_sliding_state_window && !RuntimeProfiler::IsEnabled()) {
1284 ticker_->Stop();
1285 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001286 FLAG_log_code = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001287 LOG(ISOLATE, UncheckedStringEvent("profiler", "pause"));
Andrei Popescu402d9372010-02-26 13:31:12 +00001288 }
Steve Block6ded16b2010-05-10 14:33:55 +01001289 --logging_nesting_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 }
1291 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001292}
1293
1294
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001295void Logger::ResumeProfiler() {
Steve Block44f0eee2011-05-26 01:26:41 +01001296 if (!log_->IsEnabled()) return;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001297 if (profiler_ != NULL) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001298 if (cpu_profiler_nesting_++ == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01001299 ++logging_nesting_;
Andrei Popescu402d9372010-02-26 13:31:12 +00001300 if (FLAG_prof_lazy) {
1301 profiler_->Engage();
Steve Block44f0eee2011-05-26 01:26:41 +01001302 LOG(ISOLATE, UncheckedStringEvent("profiler", "resume"));
Andrei Popescu402d9372010-02-26 13:31:12 +00001303 FLAG_log_code = true;
1304 LogCompiledFunctions();
Andrei Popescu402d9372010-02-26 13:31:12 +00001305 LogAccessorCallbacks();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001306 if (!FLAG_sliding_state_window && !ticker_->IsActive()) {
1307 ticker_->Start();
1308 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001309 }
1310 profiler_->resume();
Steve Blocka7e24c12009-10-30 11:49:00 +00001311 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001313}
1314
1315
1316// This function can be called when Log's mutex is acquired,
1317// either from main or Profiler's thread.
Steve Block44f0eee2011-05-26 01:26:41 +01001318void Logger::LogFailure() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001319 PauseProfiler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001320}
1321
1322
1323bool Logger::IsProfilerSamplerActive() {
1324 return ticker_->IsActive();
1325}
1326
1327
Ben Murdochb0fe1622011-05-05 13:52:32 +01001328class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1329 public:
1330 EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1331 Handle<Code>* code_objects,
1332 int* count)
1333 : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1334
1335 virtual void EnterContext(Context* context) {}
1336 virtual void LeaveContext(Context* context) {}
1337
1338 virtual void VisitFunction(JSFunction* function) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001339 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
1340 Object* maybe_script = sfi->script();
1341 if (maybe_script->IsScript()
1342 && !Script::cast(maybe_script)->HasValidSource()) return;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001343 if (sfis_ != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001344 sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001345 }
1346 if (code_objects_ != NULL) {
1347 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1348 code_objects_[*count_] = Handle<Code>(function->code());
1349 }
1350 *count_ = *count_ + 1;
1351 }
1352
1353 private:
1354 Handle<SharedFunctionInfo>* sfis_;
1355 Handle<Code>* code_objects_;
1356 int* count_;
1357};
1358
1359
1360static int EnumerateCompiledFunctions(Handle<SharedFunctionInfo>* sfis,
1361 Handle<Code>* code_objects) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001362 HeapIterator iterator;
Steve Block3ce2e202009-11-05 08:53:23 +00001363 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +00001364 int compiled_funcs_count = 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001365
1366 // Iterate the heap to find shared function info objects and record
1367 // the unoptimized code for them.
Leon Clarked91b9f72010-01-27 17:25:45 +00001368 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001369 if (!obj->IsSharedFunctionInfo()) continue;
1370 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1371 if (sfi->is_compiled()
1372 && (!sfi->script()->IsScript()
1373 || Script::cast(sfi->script())->HasValidSource())) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001374 if (sfis != NULL) {
Steve Block3ce2e202009-11-05 08:53:23 +00001375 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001376 }
1377 if (code_objects != NULL) {
1378 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1379 }
Steve Block3ce2e202009-11-05 08:53:23 +00001380 ++compiled_funcs_count;
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 }
1382 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001383
1384 // Iterate all optimized functions in all contexts.
1385 EnumerateOptimizedFunctionsVisitor visitor(sfis,
1386 code_objects,
1387 &compiled_funcs_count);
1388 Deoptimizer::VisitAllOptimizedFunctions(&visitor);
1389
Steve Block3ce2e202009-11-05 08:53:23 +00001390 return compiled_funcs_count;
1391}
1392
1393
Steve Blockd0582a62009-12-15 09:54:21 +00001394void Logger::LogCodeObject(Object* object) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001395 if (FLAG_log_code || FLAG_ll_prof) {
Steve Blockd0582a62009-12-15 09:54:21 +00001396 Code* code_object = Code::cast(object);
1397 LogEventsAndTags tag = Logger::STUB_TAG;
1398 const char* description = "Unknown code from the snapshot";
1399 switch (code_object->kind()) {
1400 case Code::FUNCTION:
Ben Murdochb0fe1622011-05-05 13:52:32 +01001401 case Code::OPTIMIZED_FUNCTION:
Steve Blockd0582a62009-12-15 09:54:21 +00001402 return; // We log this later using LogCompiledFunctions.
Ben Murdoch257744e2011-11-30 15:57:28 +00001403 case Code::UNARY_OP_IC: // fall through
1404 case Code::BINARY_OP_IC: // fall through
Ben Murdochb0fe1622011-05-05 13:52:32 +01001405 case Code::COMPARE_IC: // fall through
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001406 case Code::TO_BOOLEAN_IC: // fall through
Steve Blockd0582a62009-12-15 09:54:21 +00001407 case Code::STUB:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001408 description =
1409 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
Andrei Popescu31002712010-02-23 13:46:05 +00001410 if (description == NULL)
1411 description = "A stub from the snapshot";
Steve Blockd0582a62009-12-15 09:54:21 +00001412 tag = Logger::STUB_TAG;
1413 break;
1414 case Code::BUILTIN:
1415 description = "A builtin from the snapshot";
1416 tag = Logger::BUILTIN_TAG;
1417 break;
1418 case Code::KEYED_LOAD_IC:
1419 description = "A keyed load IC from the snapshot";
1420 tag = Logger::KEYED_LOAD_IC_TAG;
1421 break;
1422 case Code::LOAD_IC:
1423 description = "A load IC from the snapshot";
1424 tag = Logger::LOAD_IC_TAG;
1425 break;
1426 case Code::STORE_IC:
1427 description = "A store IC from the snapshot";
1428 tag = Logger::STORE_IC_TAG;
1429 break;
1430 case Code::KEYED_STORE_IC:
1431 description = "A keyed store IC from the snapshot";
1432 tag = Logger::KEYED_STORE_IC_TAG;
1433 break;
1434 case Code::CALL_IC:
1435 description = "A call IC from the snapshot";
1436 tag = Logger::CALL_IC_TAG;
1437 break;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001438 case Code::KEYED_CALL_IC:
1439 description = "A keyed call IC from the snapshot";
1440 tag = Logger::KEYED_CALL_IC_TAG;
1441 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001442 }
Steve Block44f0eee2011-05-26 01:26:41 +01001443 PROFILE(ISOLATE, CodeCreateEvent(tag, code_object, description));
Steve Blockd0582a62009-12-15 09:54:21 +00001444 }
1445}
1446
1447
Ben Murdochf87a2032010-10-22 12:50:53 +01001448void Logger::LogCodeInfo() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001449 if (!log_->IsEnabled() || !FLAG_ll_prof) return;
Ben Murdochf87a2032010-10-22 12:50:53 +01001450#if V8_TARGET_ARCH_IA32
1451 const char arch[] = "ia32";
1452#elif V8_TARGET_ARCH_X64
1453 const char arch[] = "x64";
1454#elif V8_TARGET_ARCH_ARM
1455 const char arch[] = "arm";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001456#elif V8_TARGET_ARCH_MIPS
1457 const char arch[] = "mips";
Ben Murdochf87a2032010-10-22 12:50:53 +01001458#else
1459 const char arch[] = "unknown";
1460#endif
Ben Murdoch257744e2011-11-30 15:57:28 +00001461 LowLevelLogWriteBytes(arch, sizeof(arch));
Ben Murdochf87a2032010-10-22 12:50:53 +01001462}
1463
1464
Ben Murdoch257744e2011-11-30 15:57:28 +00001465void Logger::RegisterSnapshotCodeName(Code* code,
1466 const char* name,
1467 int name_size) {
1468 ASSERT(Serializer::enabled());
1469 if (address_to_name_map_ == NULL) {
1470 address_to_name_map_ = new NameMap;
1471 }
1472 address_to_name_map_->Insert(code->address(), name, name_size);
1473}
1474
1475
1476void Logger::LowLevelCodeCreateEvent(Code* code,
1477 const char* name,
1478 int name_size) {
1479 if (log_->ll_output_handle_ == NULL) return;
1480 LowLevelCodeCreateStruct event;
1481 event.name_size = name_size;
1482 event.code_address = code->instruction_start();
1483 ASSERT(event.code_address == code->address() + Code::kHeaderSize);
1484 event.code_size = code->instruction_size();
1485 LowLevelLogWriteStruct(event);
1486 LowLevelLogWriteBytes(name, name_size);
1487 LowLevelLogWriteBytes(
1488 reinterpret_cast<const char*>(code->instruction_start()),
1489 code->instruction_size());
1490}
1491
1492
1493void Logger::LowLevelCodeMoveEvent(Address from, Address to) {
1494 if (log_->ll_output_handle_ == NULL) return;
1495 LowLevelCodeMoveStruct event;
1496 event.from_address = from + Code::kHeaderSize;
1497 event.to_address = to + Code::kHeaderSize;
1498 LowLevelLogWriteStruct(event);
1499}
1500
1501
1502void Logger::LowLevelCodeDeleteEvent(Address from) {
1503 if (log_->ll_output_handle_ == NULL) return;
1504 LowLevelCodeDeleteStruct event;
1505 event.address = from + Code::kHeaderSize;
1506 LowLevelLogWriteStruct(event);
1507}
1508
1509
1510void Logger::LowLevelSnapshotPositionEvent(Address addr, int pos) {
1511 if (log_->ll_output_handle_ == NULL) return;
1512 LowLevelSnapshotPositionStruct event;
1513 event.address = addr + Code::kHeaderSize;
1514 event.position = pos;
1515 LowLevelLogWriteStruct(event);
1516}
1517
1518
1519void Logger::LowLevelLogWriteBytes(const char* bytes, int size) {
1520 size_t rv = fwrite(bytes, 1, size, log_->ll_output_handle_);
1521 ASSERT(static_cast<size_t>(size) == rv);
John Reck59135872010-11-02 12:39:01 -07001522 USE(rv);
Ben Murdochf87a2032010-10-22 12:50:53 +01001523}
1524
1525
Andrei Popescu31002712010-02-23 13:46:05 +00001526void Logger::LogCodeObjects() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001527 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1528 "Logger::LogCodeObjects");
Ben Murdoch85b71792012-04-11 18:30:58 +01001529 HeapIterator iterator;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001530 AssertNoAllocation no_alloc;
Andrei Popescu31002712010-02-23 13:46:05 +00001531 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1532 if (obj->IsCode()) LogCodeObject(obj);
1533 }
1534}
1535
1536
Ben Murdoch589d6972011-11-30 16:04:58 +00001537void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1538 Handle<Code> code) {
1539 Handle<String> func_name(shared->DebugName());
1540 if (shared->script()->IsScript()) {
1541 Handle<Script> script(Script::cast(shared->script()));
1542 if (script->name()->IsString()) {
1543 Handle<String> script_name(String::cast(script->name()));
1544 int line_num = GetScriptLineNumber(script, shared->start_position());
1545 if (line_num > 0) {
1546 PROFILE(ISOLATE,
1547 CodeCreateEvent(
1548 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1549 *code, *shared,
1550 *script_name, line_num + 1));
1551 } else {
1552 // Can't distinguish eval and script here, so always use Script.
1553 PROFILE(ISOLATE,
1554 CodeCreateEvent(
1555 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1556 *code, *shared, *script_name));
1557 }
1558 } else {
1559 PROFILE(ISOLATE,
1560 CodeCreateEvent(
1561 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1562 *code, *shared, *func_name));
1563 }
1564 } else if (shared->IsApiFunction()) {
1565 // API function.
1566 FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1567 Object* raw_call_data = fun_data->call_code();
1568 if (!raw_call_data->IsUndefined()) {
1569 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1570 Object* callback_obj = call_data->callback();
1571 Address entry_point = v8::ToCData<Address>(callback_obj);
1572 PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
1573 }
1574 } else {
1575 PROFILE(ISOLATE,
1576 CodeCreateEvent(
1577 Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
1578 }
1579}
1580
1581
Steve Block3ce2e202009-11-05 08:53:23 +00001582void Logger::LogCompiledFunctions() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001583 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1584 "Logger::LogCompiledFunctions");
Steve Block3ce2e202009-11-05 08:53:23 +00001585 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001586 const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
Kristian Monsen25f61362010-05-21 11:50:48 +01001587 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001588 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1589 EnumerateCompiledFunctions(sfis.start(), code_objects.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00001590
1591 // During iteration, there can be heap allocation due to
1592 // GetScriptLineNumber call.
1593 for (int i = 0; i < compiled_funcs_count; ++i) {
Steve Block44f0eee2011-05-26 01:26:41 +01001594 if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
1595 Builtins::kLazyCompile))
1596 continue;
Ben Murdoch589d6972011-11-30 16:04:58 +00001597 LogExistingFunction(sfis[i], code_objects[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001598 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001599}
1600
Steve Blockd0582a62009-12-15 09:54:21 +00001601
1602void Logger::LogAccessorCallbacks() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001603 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1604 "Logger::LogAccessorCallbacks");
Ben Murdoch85b71792012-04-11 18:30:58 +01001605 HeapIterator iterator;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001606 AssertNoAllocation no_alloc;
Leon Clarked91b9f72010-01-27 17:25:45 +00001607 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Blockd0582a62009-12-15 09:54:21 +00001608 if (!obj->IsAccessorInfo()) continue;
1609 AccessorInfo* ai = AccessorInfo::cast(obj);
1610 if (!ai->name()->IsString()) continue;
1611 String* name = String::cast(ai->name());
1612 Address getter_entry = v8::ToCData<Address>(ai->getter());
1613 if (getter_entry != 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001614 PROFILE(ISOLATE, GetterCallbackEvent(name, getter_entry));
Steve Blockd0582a62009-12-15 09:54:21 +00001615 }
1616 Address setter_entry = v8::ToCData<Address>(ai->setter());
1617 if (setter_entry != 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001618 PROFILE(ISOLATE, SetterCallbackEvent(name, setter_entry));
Steve Blockd0582a62009-12-15 09:54:21 +00001619 }
1620 }
1621}
1622
Steve Blocka7e24c12009-10-30 11:49:00 +00001623
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001624bool Logger::SetUp() {
Steve Block44f0eee2011-05-26 01:26:41 +01001625 // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
1626 if (is_initialized_) return true;
1627 is_initialized_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001628
Ben Murdochf87a2032010-10-22 12:50:53 +01001629 // --ll-prof implies --log-code and --log-snapshot-positions.
1630 if (FLAG_ll_prof) {
Ben Murdochf87a2032010-10-22 12:50:53 +01001631 FLAG_log_snapshot_positions = true;
1632 }
1633
Steve Blocka7e24c12009-10-30 11:49:00 +00001634 // --prof_lazy controls --log-code, implies --noprof_auto.
1635 if (FLAG_prof_lazy) {
1636 FLAG_log_code = false;
1637 FLAG_prof_auto = false;
1638 }
1639
Steve Block44f0eee2011-05-26 01:26:41 +01001640 // TODO(isolates): this assert introduces cyclic dependency (logger
1641 // -> thread local top -> heap -> logger).
1642 // ASSERT(VMState::is_outermost_external());
Steve Blocka7e24c12009-10-30 11:49:00 +00001643
Steve Block44f0eee2011-05-26 01:26:41 +01001644 log_->Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +00001645
Ben Murdochf87a2032010-10-22 12:50:53 +01001646 if (FLAG_ll_prof) LogCodeInfo();
1647
Steve Block44f0eee2011-05-26 01:26:41 +01001648 Isolate* isolate = Isolate::Current();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001649 ticker_ = new Ticker(isolate, kSamplingIntervalMs);
1650
Steve Blocka7e24c12009-10-30 11:49:00 +00001651 if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001652 sliding_state_window_ = new SlidingStateWindow(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001653 }
1654
Steve Block44f0eee2011-05-26 01:26:41 +01001655 bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
1656 || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
Ben Murdoch257744e2011-11-30 15:57:28 +00001657 || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof;
Steve Block44f0eee2011-05-26 01:26:41 +01001658
Steve Block6ded16b2010-05-10 14:33:55 +01001659 if (start_logging) {
1660 logging_nesting_ = 1;
1661 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001662
1663 if (FLAG_prof) {
Steve Block44f0eee2011-05-26 01:26:41 +01001664 profiler_ = new Profiler(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001665 if (!FLAG_prof_auto) {
1666 profiler_->pause();
1667 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001668 logging_nesting_ = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 }
Steve Blockd0582a62009-12-15 09:54:21 +00001670 if (!FLAG_prof_lazy) {
1671 profiler_->Engage();
1672 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 }
1674
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001676}
1677
1678
Steve Block44f0eee2011-05-26 01:26:41 +01001679Sampler* Logger::sampler() {
1680 return ticker_;
1681}
1682
1683
Ben Murdochb0fe1622011-05-05 13:52:32 +01001684void Logger::EnsureTickerStarted() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001685 ASSERT(ticker_ != NULL);
1686 if (!ticker_->IsActive()) ticker_->Start();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001687}
1688
1689
1690void Logger::EnsureTickerStopped() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001691 if (ticker_ != NULL && ticker_->IsActive()) ticker_->Stop();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001692}
1693
1694
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001695FILE* Logger::TearDown() {
1696 if (!is_initialized_) return NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01001697 is_initialized_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001698
1699 // Stop the profiler before closing the file.
1700 if (profiler_ != NULL) {
1701 profiler_->Disengage();
1702 delete profiler_;
1703 profiler_ = NULL;
1704 }
1705
Steve Blocka7e24c12009-10-30 11:49:00 +00001706 delete sliding_state_window_;
1707 sliding_state_window_ = NULL;
1708
1709 delete ticker_;
1710 ticker_ = NULL;
1711
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001712 return log_->Close();
Steve Blocka7e24c12009-10-30 11:49:00 +00001713}
1714
1715
1716void Logger::EnableSlidingStateWindow() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001717 // If the ticker is NULL, Logger::SetUp has not been called yet. In
Steve Blocka7e24c12009-10-30 11:49:00 +00001718 // that case, we set the sliding_state_window flag so that the
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001719 // sliding window computation will be started when Logger::SetUp is
Steve Blocka7e24c12009-10-30 11:49:00 +00001720 // called.
1721 if (ticker_ == NULL) {
1722 FLAG_sliding_state_window = true;
1723 return;
1724 }
1725 // Otherwise, if the sliding state window computation has not been
1726 // started we do it now.
1727 if (sliding_state_window_ == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001728 sliding_state_window_ = new SlidingStateWindow(Isolate::Current());
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001730}
1731
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001732// Protects the state below.
1733static LazyMutex active_samplers_mutex = LAZY_MUTEX_INITIALIZER;
Steve Block44f0eee2011-05-26 01:26:41 +01001734
Steve Block44f0eee2011-05-26 01:26:41 +01001735List<Sampler*>* SamplerRegistry::active_samplers_ = NULL;
1736
1737
1738bool SamplerRegistry::IterateActiveSamplers(VisitSampler func, void* param) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001739 ScopedLock lock(active_samplers_mutex.Pointer());
Steve Block44f0eee2011-05-26 01:26:41 +01001740 for (int i = 0;
1741 ActiveSamplersExist() && i < active_samplers_->length();
1742 ++i) {
1743 func(active_samplers_->at(i), param);
1744 }
1745 return ActiveSamplersExist();
1746}
1747
1748
1749static void ComputeCpuProfiling(Sampler* sampler, void* flag_ptr) {
1750 bool* flag = reinterpret_cast<bool*>(flag_ptr);
1751 *flag |= sampler->IsProfiling();
1752}
1753
1754
1755SamplerRegistry::State SamplerRegistry::GetState() {
1756 bool flag = false;
1757 if (!IterateActiveSamplers(&ComputeCpuProfiling, &flag)) {
1758 return HAS_NO_SAMPLERS;
1759 }
1760 return flag ? HAS_CPU_PROFILING_SAMPLERS : HAS_SAMPLERS;
1761}
1762
1763
1764void SamplerRegistry::AddActiveSampler(Sampler* sampler) {
1765 ASSERT(sampler->IsActive());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001766 ScopedLock lock(active_samplers_mutex.Pointer());
Steve Block44f0eee2011-05-26 01:26:41 +01001767 if (active_samplers_ == NULL) {
1768 active_samplers_ = new List<Sampler*>;
1769 } else {
1770 ASSERT(!active_samplers_->Contains(sampler));
1771 }
1772 active_samplers_->Add(sampler);
1773}
1774
1775
1776void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) {
1777 ASSERT(sampler->IsActive());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001778 ScopedLock lock(active_samplers_mutex.Pointer());
Steve Block44f0eee2011-05-26 01:26:41 +01001779 ASSERT(active_samplers_ != NULL);
1780 bool removed = active_samplers_->RemoveElement(sampler);
1781 ASSERT(removed);
1782 USE(removed);
1783}
1784
Steve Blocka7e24c12009-10-30 11:49:00 +00001785} } // namespace v8::internal