2011-05-18 13:17:29 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2008-07-03 15:10:15 +00:00
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above
|
|
|
|
// copyright notice, this list of conditions and the following
|
|
|
|
// disclaimer in the documentation and/or other materials provided
|
|
|
|
// with the distribution.
|
|
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived
|
|
|
|
// from this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include "v8.h"
|
|
|
|
|
2009-03-24 12:47:53 +00:00
|
|
|
#include "bootstrapper.h"
|
2010-08-30 11:48:07 +00:00
|
|
|
#include "code-stubs.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "deoptimizer.h"
|
2009-11-20 12:15:46 +00:00
|
|
|
#include "global-handles.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
#include "log.h"
|
2009-03-24 12:47:53 +00:00
|
|
|
#include "macro-assembler.h"
|
2012-03-12 13:56:56 +00:00
|
|
|
#include "platform.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "runtime-profiler.h"
|
2009-03-24 12:47:53 +00:00
|
|
|
#include "serialize.h"
|
2008-10-15 08:50:22 +00:00
|
|
|
#include "string-stream.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "vm-state-inl.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2009-05-25 10:05:56 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// The Profiler samples pc and sp values for the main thread.
|
|
|
|
// Each sample is appended to a circular buffer.
|
|
|
|
// An independent thread removes data and writes it to the log.
|
|
|
|
// This design minimizes the time spent in the sampler.
|
|
|
|
//
|
|
|
|
class Profiler: public Thread {
|
|
|
|
public:
|
2011-06-10 09:42:08 +00:00
|
|
|
explicit Profiler(Isolate* isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
void Engage();
|
|
|
|
void Disengage();
|
|
|
|
|
|
|
|
// Inserts collected profiling data into buffer.
|
|
|
|
void Insert(TickSample* sample) {
|
2009-01-29 19:47:00 +00:00
|
|
|
if (paused_)
|
|
|
|
return;
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
if (Succ(head_) == tail_) {
|
|
|
|
overflow_ = true;
|
|
|
|
} else {
|
|
|
|
buffer_[head_] = *sample;
|
|
|
|
head_ = Succ(head_);
|
|
|
|
buffer_semaphore_->Signal(); // Tell we have an element.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Waits for a signal and removes profiling data.
|
|
|
|
bool Remove(TickSample* sample) {
|
|
|
|
buffer_semaphore_->Wait(); // Wait for an element.
|
|
|
|
*sample = buffer_[tail_];
|
|
|
|
bool result = overflow_;
|
|
|
|
tail_ = Succ(tail_);
|
|
|
|
overflow_ = false;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Run();
|
|
|
|
|
2009-01-29 19:47:00 +00:00
|
|
|
// Pause and Resume TickSample data collection.
|
2011-03-18 20:35:07 +00:00
|
|
|
bool paused() const { return paused_; }
|
|
|
|
void pause() { paused_ = true; }
|
|
|
|
void resume() { paused_ = false; }
|
2009-01-29 19:47:00 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
private:
|
|
|
|
// Returns the next index in the cyclic buffer.
|
|
|
|
int Succ(int index) { return (index + 1) % kBufferSize; }
|
|
|
|
|
2011-06-10 09:54:04 +00:00
|
|
|
Isolate* isolate_;
|
2008-07-03 15:10:15 +00:00
|
|
|
// Cyclic buffer for communicating profiling samples
|
|
|
|
// between the signal handler and the worker thread.
|
|
|
|
static const int kBufferSize = 128;
|
|
|
|
TickSample buffer_[kBufferSize]; // Buffer storage.
|
|
|
|
int head_; // Index to the buffer head.
|
|
|
|
int tail_; // Index to the buffer tail.
|
|
|
|
bool overflow_; // Tell whether a buffer overflow has occurred.
|
|
|
|
Semaphore* buffer_semaphore_; // Sempahore used for buffer synchronization.
|
|
|
|
|
2009-10-28 09:13:11 +00:00
|
|
|
// Tells whether profiler is engaged, that is, processing thread is stated.
|
|
|
|
bool engaged_;
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// Tells whether worker thread should continue running.
|
|
|
|
bool running_;
|
2009-01-29 19:47:00 +00:00
|
|
|
|
|
|
|
// Tells whether we are currently recording tick samples.
|
2011-03-18 20:35:07 +00:00
|
|
|
bool paused_;
|
2008-07-03 15:10:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Ticker used to provide ticks to the profiler and the sliding state
|
|
|
|
// window.
|
|
|
|
//
|
2008-08-22 13:33:59 +00:00
|
|
|
class Ticker: public Sampler {
|
2008-07-03 15:10:15 +00:00
|
|
|
public:
|
Simplify isolates access during stack iteration (WAS: Move SafeStackFrameIterator::active_count_...)
While trying to fix Mac and Windows versions for this change:
http://codereview.chromium.org/6771047/, I figured out, that we
already store an isolate in StackFrameIterator, so we can use it in
frame objects, instead of requiring it from caller.
I've changed iterators usage to the following scheme: whenever a
caller maintains an isolate pointer, it just passes it to stack
iterator, and no more worries about passing it to frame content
accessors. If a caller uses current isolate, it can omit passing it
to iterator, in this case, an iterator will use the current isolate,
too.
There was a special case with LiveEdit, which creates
detached copies of frame objects.
R=vitalyr@chromium.org
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6794019
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7499 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2011-04-05 09:01:47 +00:00
|
|
|
Ticker(Isolate* isolate, int interval):
|
2011-03-18 20:35:07 +00:00
|
|
|
Sampler(isolate, interval),
|
2010-12-07 11:31:57 +00:00
|
|
|
profiler_(NULL) {}
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
~Ticker() { if (IsActive()) Stop(); }
|
|
|
|
|
2010-10-18 12:37:07 +00:00
|
|
|
virtual void Tick(TickSample* sample) {
|
2008-07-03 15:10:15 +00:00
|
|
|
if (profiler_) profiler_->Insert(sample);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetProfiler(Profiler* profiler) {
|
2010-12-07 11:31:57 +00:00
|
|
|
ASSERT(profiler_ == NULL);
|
2008-07-03 15:10:15 +00:00
|
|
|
profiler_ = profiler;
|
2010-12-07 11:31:57 +00:00
|
|
|
IncreaseProfilingDepth();
|
2009-05-25 08:25:36 +00:00
|
|
|
if (!FLAG_prof_lazy && !IsActive()) Start();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClearProfiler() {
|
2010-12-07 11:31:57 +00:00
|
|
|
DecreaseProfilingDepth();
|
2008-07-03 15:10:15 +00:00
|
|
|
profiler_ = NULL;
|
2012-12-07 13:47:42 +00:00
|
|
|
if (IsActive()) Stop();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Profiler* profiler_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Profiler implementation.
|
|
|
|
//
|
2011-06-10 09:42:08 +00:00
|
|
|
Profiler::Profiler(Isolate* isolate)
|
2011-06-10 09:54:04 +00:00
|
|
|
: Thread("v8:Profiler"),
|
|
|
|
isolate_(isolate),
|
2011-01-04 09:09:50 +00:00
|
|
|
head_(0),
|
2009-10-28 09:13:11 +00:00
|
|
|
tail_(0),
|
|
|
|
overflow_(false),
|
|
|
|
buffer_semaphore_(OS::CreateSemaphore(0)),
|
|
|
|
engaged_(false),
|
2011-03-18 20:35:07 +00:00
|
|
|
running_(false),
|
|
|
|
paused_(false) {
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Profiler::Engage() {
|
2009-10-28 09:13:11 +00:00
|
|
|
if (engaged_) return;
|
|
|
|
engaged_ = true;
|
|
|
|
|
2013-01-29 14:39:09 +00:00
|
|
|
OS::LogSharedLibraryAddresses();
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Start thread processing the profiler buffer.
|
|
|
|
running_ = true;
|
|
|
|
Start();
|
|
|
|
|
|
|
|
// Register to get ticks.
|
2013-04-08 15:16:55 +00:00
|
|
|
Logger* logger = isolate_->logger();
|
|
|
|
logger->ticker_->SetProfiler(this);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2013-04-08 15:16:55 +00:00
|
|
|
logger->ProfilerBeginEvent();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Profiler::Disengage() {
|
2009-10-28 09:13:11 +00:00
|
|
|
if (!engaged_) return;
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// Stop receiving ticks.
|
2013-04-08 15:16:55 +00:00
|
|
|
isolate_->logger()->ticker_->ClearProfiler();
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Terminate the worker thread by setting running_ to false,
|
|
|
|
// inserting a fake element in the queue and then wait for
|
|
|
|
// the thread to terminate.
|
|
|
|
running_ = false;
|
|
|
|
TickSample sample;
|
2009-05-25 08:25:36 +00:00
|
|
|
// Reset 'paused_' flag, otherwise semaphore may not be signalled.
|
|
|
|
resume();
|
2008-07-03 15:10:15 +00:00
|
|
|
Insert(&sample);
|
|
|
|
Join();
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
LOG(ISOLATE, UncheckedStringEvent("profiler", "end"));
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Profiler::Run() {
|
|
|
|
TickSample sample;
|
2010-06-25 15:57:30 +00:00
|
|
|
bool overflow = Remove(&sample);
|
2008-07-03 15:10:15 +00:00
|
|
|
while (running_) {
|
2011-06-10 09:54:04 +00:00
|
|
|
LOG(isolate_, TickEvent(&sample, overflow));
|
2010-06-25 15:57:30 +00:00
|
|
|
overflow = Remove(&sample);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-29 16:06:25 +00:00
|
|
|
// Low-level profiling event structures.
|
|
|
|
|
|
|
|
struct LowLevelCodeCreateStruct {
|
|
|
|
static const char kTag = 'C';
|
|
|
|
|
|
|
|
int32_t name_size;
|
|
|
|
Address code_address;
|
|
|
|
int32_t code_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct LowLevelCodeMoveStruct {
|
|
|
|
static const char kTag = 'M';
|
|
|
|
|
|
|
|
Address from_address;
|
|
|
|
Address to_address;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct LowLevelCodeDeleteStruct {
|
|
|
|
static const char kTag = 'D';
|
|
|
|
|
|
|
|
Address address;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct LowLevelSnapshotPositionStruct {
|
|
|
|
static const char kTag = 'P';
|
|
|
|
|
|
|
|
Address address;
|
|
|
|
int32_t position;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const char kCodeMovingGCTag = 'G';
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
//
|
|
|
|
// Logger class implementation.
|
|
|
|
//
|
2011-03-18 20:35:07 +00:00
|
|
|
|
2011-04-29 16:06:25 +00:00
|
|
|
class Logger::NameMap {
|
|
|
|
public:
|
|
|
|
NameMap() : impl_(&PointerEquals) {}
|
|
|
|
|
|
|
|
~NameMap() {
|
|
|
|
for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) {
|
|
|
|
DeleteArray(static_cast<const char*>(p->value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Insert(Address code_address, const char* name, int name_size) {
|
|
|
|
HashMap::Entry* entry = FindOrCreateEntry(code_address);
|
|
|
|
if (entry->value == NULL) {
|
|
|
|
entry->value = CopyName(name, name_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* Lookup(Address code_address) {
|
|
|
|
HashMap::Entry* entry = FindEntry(code_address);
|
|
|
|
return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Remove(Address code_address) {
|
|
|
|
HashMap::Entry* entry = FindEntry(code_address);
|
2011-06-22 20:41:02 +00:00
|
|
|
if (entry != NULL) {
|
|
|
|
DeleteArray(static_cast<char*>(entry->value));
|
|
|
|
RemoveEntry(entry);
|
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Move(Address from, Address to) {
|
|
|
|
if (from == to) return;
|
|
|
|
HashMap::Entry* from_entry = FindEntry(from);
|
|
|
|
ASSERT(from_entry != NULL);
|
|
|
|
void* value = from_entry->value;
|
|
|
|
RemoveEntry(from_entry);
|
|
|
|
HashMap::Entry* to_entry = FindOrCreateEntry(to);
|
|
|
|
ASSERT(to_entry->value == NULL);
|
|
|
|
to_entry->value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static bool PointerEquals(void* lhs, void* rhs) {
|
|
|
|
return lhs == rhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char* CopyName(const char* name, int name_size) {
|
|
|
|
char* result = NewArray<char>(name_size + 1);
|
|
|
|
for (int i = 0; i < name_size; ++i) {
|
|
|
|
char c = name[i];
|
|
|
|
if (c == '\0') c = ' ';
|
|
|
|
result[i] = c;
|
|
|
|
}
|
|
|
|
result[name_size] = '\0';
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
HashMap::Entry* FindOrCreateEntry(Address code_address) {
|
|
|
|
return impl_.Lookup(code_address, ComputePointerHash(code_address), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
HashMap::Entry* FindEntry(Address code_address) {
|
|
|
|
return impl_.Lookup(code_address, ComputePointerHash(code_address), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveEntry(HashMap::Entry* entry) {
|
|
|
|
impl_.Remove(entry->key, entry->hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
HashMap impl_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(NameMap);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Logger::NameBuffer {
|
|
|
|
public:
|
|
|
|
NameBuffer() { Reset(); }
|
|
|
|
|
|
|
|
void Reset() {
|
|
|
|
utf8_pos_ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppendString(String* str) {
|
|
|
|
if (str == NULL) return;
|
2012-03-12 12:35:28 +00:00
|
|
|
int uc16_length = Min(str->length(), kUtf16BufferSize);
|
|
|
|
String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
|
|
|
|
int previous = unibrow::Utf16::kNoPreviousCharacter;
|
2011-04-29 16:06:25 +00:00
|
|
|
for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
|
2012-03-12 12:35:28 +00:00
|
|
|
uc16 c = utf16_buffer[i];
|
2013-01-09 10:30:54 +00:00
|
|
|
if (c <= unibrow::Utf8::kMaxOneByteChar) {
|
2011-04-29 16:26:37 +00:00
|
|
|
utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
|
2011-04-29 16:06:25 +00:00
|
|
|
} else {
|
2012-03-12 12:35:28 +00:00
|
|
|
int char_length = unibrow::Utf8::Length(c, previous);
|
2011-04-29 16:06:25 +00:00
|
|
|
if (utf8_pos_ + char_length > kUtf8BufferSize) break;
|
2012-03-12 12:35:28 +00:00
|
|
|
unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
|
2011-04-29 16:06:25 +00:00
|
|
|
utf8_pos_ += char_length;
|
|
|
|
}
|
2012-03-12 12:35:28 +00:00
|
|
|
previous = c;
|
2011-04-29 16:06:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppendBytes(const char* bytes, int size) {
|
|
|
|
size = Min(size, kUtf8BufferSize - utf8_pos_);
|
2013-04-16 12:30:51 +00:00
|
|
|
OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
|
2011-04-29 16:06:25 +00:00
|
|
|
utf8_pos_ += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppendBytes(const char* bytes) {
|
|
|
|
AppendBytes(bytes, StrLength(bytes));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppendByte(char c) {
|
|
|
|
if (utf8_pos_ >= kUtf8BufferSize) return;
|
|
|
|
utf8_buffer_[utf8_pos_++] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppendInt(int n) {
|
|
|
|
Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
|
|
|
|
int size = OS::SNPrintF(buffer, "%d", n);
|
|
|
|
if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
|
|
|
|
utf8_pos_ += size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-04 15:00:57 +00:00
|
|
|
void AppendHex(uint32_t n) {
|
|
|
|
Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
|
|
|
|
int size = OS::SNPrintF(buffer, "%x", n);
|
|
|
|
if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
|
|
|
|
utf8_pos_ += size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-29 16:06:25 +00:00
|
|
|
const char* get() { return utf8_buffer_; }
|
|
|
|
int size() const { return utf8_pos_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
static const int kUtf8BufferSize = 512;
|
2012-03-12 12:35:28 +00:00
|
|
|
static const int kUtf16BufferSize = 128;
|
2011-04-29 16:06:25 +00:00
|
|
|
|
|
|
|
int utf8_pos_;
|
|
|
|
char utf8_buffer_[kUtf8BufferSize];
|
2012-03-12 12:35:28 +00:00
|
|
|
uc16 utf16_buffer[kUtf16BufferSize];
|
2011-04-29 16:06:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-02-15 09:27:10 +00:00
|
|
|
Logger::Logger(Isolate* isolate)
|
|
|
|
: isolate_(isolate),
|
|
|
|
ticker_(NULL),
|
2011-03-18 20:35:07 +00:00
|
|
|
profiler_(NULL),
|
|
|
|
log_events_(NULL),
|
|
|
|
logging_nesting_(0),
|
|
|
|
cpu_profiler_nesting_(0),
|
|
|
|
log_(new Log(this)),
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_(new NameBuffer),
|
|
|
|
address_to_name_map_(NULL),
|
2011-03-18 20:35:07 +00:00
|
|
|
is_initialized_(false),
|
2012-08-28 14:43:28 +00:00
|
|
|
code_event_handler_(NULL),
|
2011-03-18 20:35:07 +00:00
|
|
|
last_address_(NULL),
|
|
|
|
prev_sp_(NULL),
|
|
|
|
prev_function_(NULL),
|
|
|
|
prev_to_(NULL),
|
2012-11-22 13:04:11 +00:00
|
|
|
prev_code_(NULL),
|
|
|
|
epoch_(0) {
|
2011-03-18 20:35:07 +00:00
|
|
|
}
|
|
|
|
|
2011-04-29 16:06:25 +00:00
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
Logger::~Logger() {
|
2011-04-29 16:06:25 +00:00
|
|
|
delete address_to_name_map_;
|
|
|
|
delete name_buffer_;
|
2011-03-18 20:35:07 +00:00
|
|
|
delete log_;
|
|
|
|
}
|
2009-06-08 13:39:48 +00:00
|
|
|
|
2011-04-29 16:06:25 +00:00
|
|
|
|
2012-08-28 14:43:28 +00:00
|
|
|
void Logger::IssueCodeAddedEvent(Code* code,
|
2013-02-18 18:06:12 +00:00
|
|
|
Script* script,
|
2012-08-28 14:43:28 +00:00
|
|
|
const char* name,
|
|
|
|
size_t name_len) {
|
|
|
|
JitCodeEvent event;
|
2013-02-18 18:06:12 +00:00
|
|
|
memset(&event, 0, sizeof(event));
|
2012-08-28 14:43:28 +00:00
|
|
|
event.type = JitCodeEvent::CODE_ADDED;
|
|
|
|
event.code_start = code->instruction_start();
|
|
|
|
event.code_len = code->instruction_size();
|
2013-02-18 18:06:12 +00:00
|
|
|
Handle<Script> script_handle =
|
|
|
|
script != NULL ? Handle<Script>(script) : Handle<Script>();
|
2013-06-13 09:27:09 +00:00
|
|
|
event.script = ToApiHandle<v8::Script>(script_handle);
|
2012-08-28 14:43:28 +00:00
|
|
|
event.name.str = name;
|
|
|
|
event.name.len = name_len;
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::IssueCodeMovedEvent(Address from, Address to) {
|
|
|
|
Code* from_code = Code::cast(HeapObject::FromAddress(from));
|
|
|
|
|
|
|
|
JitCodeEvent event;
|
|
|
|
event.type = JitCodeEvent::CODE_MOVED;
|
|
|
|
event.code_start = from_code->instruction_start();
|
|
|
|
event.code_len = from_code->instruction_size();
|
|
|
|
|
|
|
|
// Calculate the header size.
|
|
|
|
const size_t header_size =
|
|
|
|
from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
|
|
|
|
|
|
|
|
// Calculate the new start address of the instructions.
|
|
|
|
event.new_code_start =
|
|
|
|
reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::IssueCodeRemovedEvent(Address from) {
|
|
|
|
Code* from_code = Code::cast(HeapObject::FromAddress(from));
|
|
|
|
|
|
|
|
JitCodeEvent event;
|
|
|
|
event.type = JitCodeEvent::CODE_REMOVED;
|
|
|
|
event.code_start = from_code->instruction_start();
|
|
|
|
event.code_len = from_code->instruction_size();
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
}
|
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
void Logger::IssueAddCodeLinePosInfoEvent(
|
|
|
|
void* jit_handler_data,
|
|
|
|
int pc_offset,
|
|
|
|
int position,
|
|
|
|
JitCodeEvent::PositionType position_type) {
|
|
|
|
JitCodeEvent event;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
|
|
|
|
event.user_data = jit_handler_data;
|
|
|
|
event.line_info.offset = pc_offset;
|
|
|
|
event.line_info.pos = position;
|
|
|
|
event.line_info.position_type = position_type;
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void* Logger::IssueStartCodePosInfoEvent() {
|
|
|
|
JitCodeEvent event;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
return event.user_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::IssueEndCodePosInfoEvent(Code* code, void* jit_handler_data) {
|
|
|
|
JitCodeEvent event;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
|
|
|
|
event.code_start = code->instruction_start();
|
|
|
|
event.user_data = jit_handler_data;
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
|
2010-12-07 13:24:22 +00:00
|
|
|
#define DECLARE_EVENT(ignore1, name) name,
|
2011-03-18 20:35:07 +00:00
|
|
|
static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
|
2010-12-07 13:24:22 +00:00
|
|
|
LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
|
2009-06-08 13:39:48 +00:00
|
|
|
};
|
2010-12-07 13:24:22 +00:00
|
|
|
#undef DECLARE_EVENT
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2009-05-05 15:57:47 +00:00
|
|
|
|
2009-05-29 06:56:23 +00:00
|
|
|
void Logger::ProfilerBeginEvent() {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-05-29 06:56:23 +00:00
|
|
|
msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
|
2009-06-08 13:39:48 +00:00
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
2009-02-17 08:21:24 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::StringEvent(const char* name, const char* value) {
|
2009-02-11 07:38:31 +00:00
|
|
|
if (FLAG_log) UncheckedStringEvent(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::UncheckedStringEvent(const char* name, const char* value) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("%s,\"%s\"\n", name, value);
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::IntEvent(const char* name, int value) {
|
2010-03-01 10:41:34 +00:00
|
|
|
if (FLAG_log) UncheckedIntEvent(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-30 07:22:53 +00:00
|
|
|
void Logger::IntPtrTEvent(const char* name, intptr_t value) {
|
|
|
|
if (FLAG_log) UncheckedIntPtrTEvent(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-01 10:41:34 +00:00
|
|
|
void Logger::UncheckedIntEvent(const char* name, int value) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("%s,%d\n", name, value);
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-30 07:22:53 +00:00
|
|
|
void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2010-09-30 07:22:53 +00:00
|
|
|
msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
|
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::HandleEvent(const char* name, Object** location) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_handles) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-05-15 09:58:40 +00:00
|
|
|
msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ApiEvent is private so all the calls come from the Logger class. It is the
|
2009-05-05 15:57:47 +00:00
|
|
|
// caller's responsibility to ensure that log is enabled and that
|
2008-07-03 15:10:15 +00:00
|
|
|
// FLAG_log_api is true.
|
|
|
|
void Logger::ApiEvent(const char* format, ...) {
|
2011-03-18 20:35:07 +00:00
|
|
|
ASSERT(log_->IsEnabled() && FLAG_log_api);
|
|
|
|
LogMessageBuilder msg(this);
|
2008-07-03 15:10:15 +00:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
2009-06-15 15:49:03 +00:00
|
|
|
msg.AppendVA(format, ap);
|
2009-02-17 12:49:35 +00:00
|
|
|
va_end(ap);
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::ApiNamedSecurityCheck(Object* key) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
2008-07-03 15:10:15 +00:00
|
|
|
if (key->IsString()) {
|
2011-09-09 22:39:47 +00:00
|
|
|
SmartArrayPointer<char> str =
|
2008-07-03 15:10:15 +00:00
|
|
|
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
ApiEvent("api,check-security,\"%s\"\n", *str);
|
2013-03-04 15:00:57 +00:00
|
|
|
} else if (key->IsSymbol()) {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(key);
|
|
|
|
if (symbol->name()->IsUndefined()) {
|
|
|
|
ApiEvent("api,check-security,symbol(hash %x)\n",
|
|
|
|
Symbol::cast(key)->Hash());
|
|
|
|
} else {
|
|
|
|
SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
|
|
|
|
DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
|
|
|
|
*str,
|
|
|
|
Symbol::cast(key)->Hash());
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
} else if (key->IsUndefined()) {
|
|
|
|
ApiEvent("api,check-security,undefined\n");
|
|
|
|
} else {
|
|
|
|
ApiEvent("api,check-security,['no-name']\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::SharedLibraryEvent(const char* library_path,
|
2009-06-16 12:52:02 +00:00
|
|
|
uintptr_t start,
|
|
|
|
uintptr_t end) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_prof) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-06-16 12:52:02 +00:00
|
|
|
msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
|
|
|
|
library_path,
|
|
|
|
start,
|
|
|
|
end);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::SharedLibraryEvent(const wchar_t* library_path,
|
2009-06-16 12:52:02 +00:00
|
|
|
uintptr_t start,
|
|
|
|
uintptr_t end) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_prof) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-06-16 12:52:02 +00:00
|
|
|
msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
|
|
|
|
library_path,
|
|
|
|
start,
|
|
|
|
end);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2008-09-12 17:25:38 +00:00
|
|
|
|
2013-01-28 13:55:40 +00:00
|
|
|
void Logger::TimerEvent(StartEnd se, const char* name) {
|
2012-11-26 08:56:59 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
2012-12-05 16:22:14 +00:00
|
|
|
ASSERT(FLAG_log_internal_timer_events);
|
2012-11-22 13:04:11 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2013-01-28 13:55:40 +00:00
|
|
|
int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
|
|
|
|
const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
|
|
|
|
: "timer-event-end,\"%s\",%ld\n";
|
|
|
|
msg.Append(format, name, since_epoch);
|
2012-11-22 13:04:11 +00:00
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-24 14:44:08 +00:00
|
|
|
void Logger::EnterExternal(Isolate* isolate) {
|
|
|
|
LOG(isolate, TimerEvent(START, TimerEventScope::v8_external));
|
|
|
|
ASSERT(isolate->current_vm_state() == JS);
|
|
|
|
isolate->set_current_vm_state(EXTERNAL);
|
2012-11-28 15:11:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-24 14:44:08 +00:00
|
|
|
void Logger::LeaveExternal(Isolate* isolate) {
|
|
|
|
LOG(isolate, TimerEvent(END, TimerEventScope::v8_external));
|
|
|
|
ASSERT(isolate->current_vm_state() == EXTERNAL);
|
|
|
|
isolate->set_current_vm_state(JS);
|
2012-11-28 15:11:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-28 13:55:40 +00:00
|
|
|
void Logger::TimerEventScope::LogTimerEvent(StartEnd se) {
|
|
|
|
LOG(isolate_, TimerEvent(se, name_));
|
2012-11-26 08:56:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-22 13:04:11 +00:00
|
|
|
const char* Logger::TimerEventScope::v8_recompile_synchronous =
|
|
|
|
"V8.RecompileSynchronous";
|
|
|
|
const char* Logger::TimerEventScope::v8_recompile_parallel =
|
|
|
|
"V8.RecompileParallel";
|
|
|
|
const char* Logger::TimerEventScope::v8_compile_full_code =
|
|
|
|
"V8.CompileFullCode";
|
|
|
|
const char* Logger::TimerEventScope::v8_execute = "V8.Execute";
|
2013-01-28 13:55:40 +00:00
|
|
|
const char* Logger::TimerEventScope::v8_external = "V8.External";
|
2012-11-22 13:04:11 +00:00
|
|
|
|
|
|
|
|
2008-09-23 11:45:43 +00:00
|
|
|
void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
|
2008-09-11 12:57:27 +00:00
|
|
|
// Prints "/" + re.source + "/" +
|
2008-09-11 11:24:45 +00:00
|
|
|
// (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2008-09-11 11:24:45 +00:00
|
|
|
|
|
|
|
Handle<Object> source = GetProperty(regexp, "source");
|
|
|
|
if (!source->IsString()) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("no source");
|
2008-09-11 11:24:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-24 08:40:02 +00:00
|
|
|
switch (regexp->TypeTag()) {
|
2008-10-02 15:35:28 +00:00
|
|
|
case JSRegExp::ATOM:
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('a');
|
2008-10-02 15:35:28 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('/');
|
|
|
|
msg.AppendDetailed(*Handle<String>::cast(source), false);
|
|
|
|
msg.Append('/');
|
2008-09-11 11:24:45 +00:00
|
|
|
|
|
|
|
// global flag
|
|
|
|
Handle<Object> global = GetProperty(regexp, "global");
|
|
|
|
if (global->IsTrue()) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('g');
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
// ignorecase flag
|
|
|
|
Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
|
|
|
|
if (ignorecase->IsTrue()) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('i');
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
// multiline flag
|
|
|
|
Handle<Object> multiline = GetProperty(regexp, "multiline");
|
|
|
|
if (multiline->IsTrue()) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('m');
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
|
|
|
|
msg.WriteToLogFile();
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-24 08:40:02 +00:00
|
|
|
void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_regexp) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("regexp-compile,");
|
2008-09-11 11:24:45 +00:00
|
|
|
LogRegExpSource(regexp);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append(in_cache ? ",hit\n" : ",miss\n");
|
|
|
|
msg.WriteToLogFile();
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-08 15:16:55 +00:00
|
|
|
void Logger::LogRuntime(Vector<const char> format,
|
2013-02-15 09:27:10 +00:00
|
|
|
JSArray* args) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_runtime) return;
|
2013-04-08 15:16:55 +00:00
|
|
|
HandleScope scope(isolate_);
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2009-01-06 13:24:52 +00:00
|
|
|
for (int i = 0; i < format.length(); i++) {
|
|
|
|
char c = format[i];
|
|
|
|
if (c == '%' && i <= format.length() - 2) {
|
|
|
|
i++;
|
|
|
|
ASSERT('0' <= format[i] && format[i] <= '9');
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* maybe = args->GetElement(format[i] - '0');
|
|
|
|
Object* obj;
|
|
|
|
if (!maybe->ToObject(&obj)) {
|
|
|
|
msg.Append("<exception>");
|
|
|
|
continue;
|
|
|
|
}
|
2009-01-06 13:24:52 +00:00
|
|
|
i++;
|
|
|
|
switch (format[i]) {
|
|
|
|
case 's':
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.AppendDetailed(String::cast(obj), false);
|
2009-01-06 13:24:52 +00:00
|
|
|
break;
|
|
|
|
case 'S':
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.AppendDetailed(String::cast(obj), true);
|
2009-01-06 13:24:52 +00:00
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
|
|
|
|
break;
|
|
|
|
case 'x':
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("0x%x", Smi::cast(obj)->value());
|
2009-01-06 13:24:52 +00:00
|
|
|
break;
|
|
|
|
case 'i':
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("%i", Smi::cast(obj)->value());
|
2009-01-06 13:24:52 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
} else {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append(c);
|
2009-01-06 13:24:52 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::ApiIndexedSecurityCheck(uint32_t index) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
2008-07-03 15:10:15 +00:00
|
|
|
ApiEvent("api,check-security,%u\n", index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::ApiNamedPropertyAccess(const char* tag,
|
|
|
|
JSObject* holder,
|
|
|
|
Object* name) {
|
2013-03-04 15:00:57 +00:00
|
|
|
ASSERT(name->IsName());
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
2008-07-03 15:10:15 +00:00
|
|
|
String* class_name_obj = holder->class_name();
|
2011-09-09 22:39:47 +00:00
|
|
|
SmartArrayPointer<char> class_name =
|
2008-07-03 15:10:15 +00:00
|
|
|
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
SmartArrayPointer<char> property_name =
|
|
|
|
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
uint32_t hash = symbol->Hash();
|
|
|
|
if (symbol->name()->IsUndefined()) {
|
|
|
|
ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
|
|
|
|
} else {
|
|
|
|
SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
|
|
|
|
DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
|
|
|
|
tag, *class_name, *str, hash);
|
|
|
|
}
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::ApiIndexedPropertyAccess(const char* tag,
|
|
|
|
JSObject* holder,
|
|
|
|
uint32_t index) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
2008-07-03 15:10:15 +00:00
|
|
|
String* class_name_obj = holder->class_name();
|
2011-09-09 22:39:47 +00:00
|
|
|
SmartArrayPointer<char> class_name =
|
2008-07-03 15:10:15 +00:00
|
|
|
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2011-03-28 08:44:30 +00:00
|
|
|
ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
2008-07-03 15:10:15 +00:00
|
|
|
String* class_name_obj = object->class_name();
|
2011-09-09 22:39:47 +00:00
|
|
|
SmartArrayPointer<char> class_name =
|
2008-07-03 15:10:15 +00:00
|
|
|
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2011-03-28 08:44:30 +00:00
|
|
|
ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::ApiEntryCall(const char* name) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
2011-03-28 08:44:30 +00:00
|
|
|
ApiEvent("api,%s\n", name);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::NewEvent(const char* name, void* object, size_t size) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-05-15 09:58:40 +00:00
|
|
|
msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
|
2009-02-17 12:49:35 +00:00
|
|
|
static_cast<unsigned int>(size));
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::DeleteEvent(const char* name, void* object) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-05-15 09:58:40 +00:00
|
|
|
msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
void Logger::NewEventStatic(const char* name, void* object, size_t size) {
|
2013-04-08 15:16:55 +00:00
|
|
|
Isolate::Current()->logger()->NewEvent(name, object, size);
|
2011-03-18 20:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::DeleteEventStatic(const char* name, void* object) {
|
2013-04-08 15:16:55 +00:00
|
|
|
Isolate::Current()->logger()->DeleteEvent(name, object);
|
2011-03-18 20:35:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-04 15:00:57 +00:00
|
|
|
void Logger::CallbackEventInternal(const char* prefix, Name* name,
|
2009-11-25 16:39:18 +00:00
|
|
|
Address entry_point) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,-3,",
|
2010-12-07 13:24:22 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
|
|
|
kLogEventsNames[CALLBACK_TAG]);
|
2009-11-23 09:19:24 +00:00
|
|
|
msg.AppendAddress(entry_point);
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
SmartArrayPointer<char> str =
|
|
|
|
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
msg.Append(",1,\"%s%s\"", prefix, *str);
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
if (symbol->name()->IsUndefined()) {
|
|
|
|
msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
|
|
|
|
} else {
|
|
|
|
SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
|
|
|
|
DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash());
|
|
|
|
}
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2009-11-23 09:19:24 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2009-11-25 16:39:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 15:00:57 +00:00
|
|
|
void Logger::CallbackEvent(Name* name, Address entry_point) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
2013-03-04 15:00:57 +00:00
|
|
|
CallbackEventInternal("", name, entry_point);
|
2009-11-25 16:39:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 15:00:57 +00:00
|
|
|
void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
2013-03-04 15:00:57 +00:00
|
|
|
CallbackEventInternal("get ", name, entry_point);
|
2009-11-25 16:39:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 15:00:57 +00:00
|
|
|
void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
2013-03-04 15:00:57 +00:00
|
|
|
CallbackEventInternal("set ", name, entry_point);
|
2009-11-23 09:19:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-08 13:39:48 +00:00
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
const char* comment) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->Reset();
|
|
|
|
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
|
|
|
name_buffer_->AppendByte(':');
|
|
|
|
name_buffer_->AppendBytes(comment);
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) {
|
2013-02-18 18:06:12 +00:00
|
|
|
IssueCodeAddedEvent(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
if (!log_->IsEnabled()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (Serializer::enabled()) {
|
|
|
|
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (!FLAG_log_code) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,%d,",
|
2010-12-07 13:24:22 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
2012-11-28 11:01:10 +00:00
|
|
|
kLogEventsNames[tag],
|
|
|
|
code->kind());
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.AppendAddress(code->address());
|
2011-02-22 16:31:24 +00:00
|
|
|
msg.Append(",%d,\"", code->ExecutableSize());
|
2008-07-03 15:10:15 +00:00
|
|
|
for (const char* p = comment; *p != '\0'; p++) {
|
2009-02-17 12:49:35 +00:00
|
|
|
if (*p == '"') {
|
|
|
|
msg.Append('\\');
|
|
|
|
}
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.Append(*p);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.Append('"');
|
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-22 16:31:24 +00:00
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
|
|
|
Code* code,
|
2013-03-04 15:00:57 +00:00
|
|
|
Name* name) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->Reset();
|
|
|
|
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
|
|
|
name_buffer_->AppendByte(':');
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
name_buffer_->AppendString(String::cast(name));
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
name_buffer_->AppendBytes("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
name_buffer_->AppendBytes("\"");
|
|
|
|
name_buffer_->AppendString(String::cast(symbol->name()));
|
|
|
|
name_buffer_->AppendBytes("\" ");
|
|
|
|
}
|
|
|
|
name_buffer_->AppendBytes("hash ");
|
|
|
|
name_buffer_->AppendHex(symbol->Hash());
|
2013-03-04 15:00:57 +00:00
|
|
|
name_buffer_->AppendByte(')');
|
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) {
|
2013-02-18 18:06:12 +00:00
|
|
|
IssueCodeAddedEvent(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
if (!log_->IsEnabled()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
2011-02-22 16:31:24 +00:00
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
if (Serializer::enabled()) {
|
|
|
|
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (!FLAG_log_code) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,%d,",
|
2011-04-29 16:06:25 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
2012-11-28 11:01:10 +00:00
|
|
|
kLogEventsNames[tag],
|
|
|
|
code->kind());
|
2011-04-29 16:06:25 +00:00
|
|
|
msg.AppendAddress(code->address());
|
2013-03-04 15:00:57 +00:00
|
|
|
msg.Append(",%d,", code->ExecutableSize());
|
|
|
|
if (name->IsString()) {
|
|
|
|
msg.Append('"');
|
|
|
|
msg.AppendDetailed(String::cast(name), false);
|
|
|
|
msg.Append('"');
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
msg.Append("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
msg.Append("\"");
|
|
|
|
msg.AppendDetailed(String::cast(symbol->name()), false);
|
|
|
|
msg.Append("\" ");
|
|
|
|
}
|
|
|
|
msg.Append("hash %x)", symbol->Hash());
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2011-02-22 16:31:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ComputeMarker must only be used when SharedFunctionInfo is known.
|
|
|
|
static const char* ComputeMarker(Code* code) {
|
|
|
|
switch (code->kind()) {
|
|
|
|
case Code::FUNCTION: return code->optimizable() ? "~" : "";
|
|
|
|
case Code::OPTIMIZED_FUNCTION: return "*";
|
|
|
|
default: return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
2013-05-14 22:51:33 +00:00
|
|
|
CompilationInfo* info,
|
2013-03-04 15:00:57 +00:00
|
|
|
Name* name) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->Reset();
|
|
|
|
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
|
|
|
name_buffer_->AppendByte(':');
|
2011-05-20 15:45:06 +00:00
|
|
|
name_buffer_->AppendBytes(ComputeMarker(code));
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
name_buffer_->AppendString(String::cast(name));
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
name_buffer_->AppendBytes("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
name_buffer_->AppendBytes("\"");
|
|
|
|
name_buffer_->AppendString(String::cast(symbol->name()));
|
|
|
|
name_buffer_->AppendBytes("\" ");
|
|
|
|
}
|
|
|
|
name_buffer_->AppendBytes("hash ");
|
|
|
|
name_buffer_->AppendHex(symbol->Hash());
|
2013-03-04 15:00:57 +00:00
|
|
|
name_buffer_->AppendByte(')');
|
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) {
|
2013-02-18 18:06:12 +00:00
|
|
|
Script* script =
|
|
|
|
shared->script()->IsScript() ? Script::cast(shared->script()) : NULL;
|
|
|
|
IssueCodeAddedEvent(code,
|
|
|
|
script,
|
|
|
|
name_buffer_->get(),
|
|
|
|
name_buffer_->size());
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
if (!log_->IsEnabled()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (Serializer::enabled()) {
|
|
|
|
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (!FLAG_log_code) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
if (code == Isolate::Current()->builtins()->builtin(
|
2011-03-23 13:40:07 +00:00
|
|
|
Builtins::kLazyCompile))
|
2011-03-18 20:35:07 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
LogMessageBuilder msg(this);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,%d,",
|
2010-12-07 13:24:22 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
2012-11-28 11:01:10 +00:00
|
|
|
kLogEventsNames[tag],
|
|
|
|
code->kind());
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.AppendAddress(code->address());
|
2013-03-04 15:00:57 +00:00
|
|
|
msg.Append(",%d,", code->ExecutableSize());
|
|
|
|
if (name->IsString()) {
|
|
|
|
SmartArrayPointer<char> str =
|
|
|
|
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
msg.Append("\"%s\"", *str);
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
msg.Append("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
msg.Append("\"");
|
|
|
|
msg.AppendDetailed(String::cast(symbol->name()), false);
|
|
|
|
msg.Append("\" ");
|
|
|
|
}
|
|
|
|
msg.Append("hash %x)", symbol->Hash());
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
|
|
|
msg.Append(',');
|
2011-02-22 16:31:24 +00:00
|
|
|
msg.AppendAddress(shared->address());
|
|
|
|
msg.Append(",%s", ComputeMarker(code));
|
2009-06-18 07:59:13 +00:00
|
|
|
msg.Append('\n');
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-22 16:31:24 +00:00
|
|
|
// Although, it is possible to extract source and line from
|
|
|
|
// the SharedFunctionInfo object, we left it to caller
|
|
|
|
// to leave logging functions free from heap allocations.
|
2009-06-08 13:39:48 +00:00
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
2011-02-22 16:31:24 +00:00
|
|
|
Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
2013-05-14 22:51:33 +00:00
|
|
|
CompilationInfo* info,
|
2013-03-04 15:00:57 +00:00
|
|
|
Name* source, int line) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->Reset();
|
|
|
|
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
|
|
|
name_buffer_->AppendByte(':');
|
2011-05-20 15:45:06 +00:00
|
|
|
name_buffer_->AppendBytes(ComputeMarker(code));
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->AppendString(shared->DebugName());
|
|
|
|
name_buffer_->AppendByte(' ');
|
2013-03-04 15:00:57 +00:00
|
|
|
if (source->IsString()) {
|
|
|
|
name_buffer_->AppendString(String::cast(source));
|
|
|
|
} else {
|
|
|
|
name_buffer_->AppendBytes("symbol(hash ");
|
|
|
|
name_buffer_->AppendHex(Name::cast(source)->Hash());
|
|
|
|
name_buffer_->AppendByte(')');
|
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->AppendByte(':');
|
|
|
|
name_buffer_->AppendInt(line);
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) {
|
2013-02-18 18:06:12 +00:00
|
|
|
Script* script =
|
|
|
|
shared->script()->IsScript() ? Script::cast(shared->script()) : NULL;
|
|
|
|
IssueCodeAddedEvent(code,
|
|
|
|
script,
|
|
|
|
name_buffer_->get(),
|
|
|
|
name_buffer_->size());
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
if (!log_->IsEnabled()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (Serializer::enabled()) {
|
|
|
|
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (!FLAG_log_code) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2011-09-09 22:39:47 +00:00
|
|
|
SmartArrayPointer<char> name =
|
2011-02-22 16:31:24 +00:00
|
|
|
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,%d,",
|
2010-12-07 13:24:22 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
2012-11-28 11:01:10 +00:00
|
|
|
kLogEventsNames[tag],
|
|
|
|
code->kind());
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.AppendAddress(code->address());
|
2013-03-04 15:00:57 +00:00
|
|
|
msg.Append(",%d,\"%s ", code->ExecutableSize(), *name);
|
|
|
|
if (source->IsString()) {
|
|
|
|
SmartArrayPointer<char> sourcestr =
|
|
|
|
String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
msg.Append("%s", *sourcestr);
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(source);
|
|
|
|
msg.Append("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
msg.Append("\"");
|
|
|
|
msg.AppendDetailed(String::cast(symbol->name()), false);
|
|
|
|
msg.Append("\" ");
|
|
|
|
}
|
|
|
|
msg.Append("hash %x)", symbol->Hash());
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
|
|
|
msg.Append(":%d\",", line);
|
2011-02-22 16:31:24 +00:00
|
|
|
msg.AppendAddress(shared->address());
|
|
|
|
msg.Append(",%s", ComputeMarker(code));
|
2009-06-18 07:59:13 +00:00
|
|
|
msg.Append('\n');
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2009-02-03 10:52:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-08 13:39:48 +00:00
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->Reset();
|
|
|
|
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
|
|
|
name_buffer_->AppendByte(':');
|
|
|
|
name_buffer_->AppendInt(args_count);
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) {
|
2013-02-18 18:06:12 +00:00
|
|
|
IssueCodeAddedEvent(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
if (!log_->IsEnabled()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (Serializer::enabled()) {
|
|
|
|
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (!FLAG_log_code) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,%d,",
|
2010-12-07 13:24:22 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
2012-11-28 11:01:10 +00:00
|
|
|
kLogEventsNames[tag],
|
|
|
|
code->kind());
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.AppendAddress(code->address());
|
2009-06-18 07:59:13 +00:00
|
|
|
msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
|
|
|
|
msg.Append('\n');
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-19 16:45:11 +00:00
|
|
|
void Logger::CodeMovingGCEvent() {
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_ll_prof) return;
|
|
|
|
LowLevelLogWriteBytes(&kCodeMovingGCTag, sizeof(kCodeMovingGCTag));
|
2010-10-19 16:45:11 +00:00
|
|
|
OS::SignalCodeMovingGC();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-31 09:06:37 +00:00
|
|
|
void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
2011-04-29 16:06:25 +00:00
|
|
|
name_buffer_->Reset();
|
|
|
|
name_buffer_->AppendBytes(kLogEventsNames[REG_EXP_TAG]);
|
|
|
|
name_buffer_->AppendByte(':');
|
|
|
|
name_buffer_->AppendString(source);
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) {
|
2013-02-18 18:06:12 +00:00
|
|
|
IssueCodeAddedEvent(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
if (!log_->IsEnabled()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
LowLevelCodeCreateEvent(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (Serializer::enabled()) {
|
|
|
|
RegisterSnapshotCodeName(code, name_buffer_->get(), name_buffer_->size());
|
|
|
|
}
|
|
|
|
if (!FLAG_log_code) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2012-11-28 11:01:10 +00:00
|
|
|
msg.Append("%s,%s,-2,",
|
2010-12-07 13:24:22 +00:00
|
|
|
kLogEventsNames[CODE_CREATION_EVENT],
|
|
|
|
kLogEventsNames[REG_EXP_TAG]);
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.AppendAddress(code->address());
|
|
|
|
msg.Append(",%d,\"", code->ExecutableSize());
|
2009-03-31 09:06:37 +00:00
|
|
|
msg.AppendDetailed(source, false);
|
2009-06-18 07:59:13 +00:00
|
|
|
msg.Append('\"');
|
|
|
|
msg.Append('\n');
|
2009-03-31 09:06:37 +00:00
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::CodeMoveEvent(Address from, Address to) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) IssueCodeMovedEvent(from, to);
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
if (FLAG_ll_prof) LowLevelCodeMoveEvent(from, to);
|
|
|
|
if (Serializer::enabled() && address_to_name_map_ != NULL) {
|
|
|
|
address_to_name_map_->Move(from, to);
|
|
|
|
}
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
MoveEventInternal(CODE_MOVE_EVENT, from, to);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::CodeDeleteEvent(Address from) {
|
2012-08-28 14:43:28 +00:00
|
|
|
if (code_event_handler_ != NULL) IssueCodeRemovedEvent(from);
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
if (FLAG_ll_prof) LowLevelCodeDeleteEvent(from);
|
|
|
|
if (Serializer::enabled() && address_to_name_map_ != NULL) {
|
|
|
|
address_to_name_map_->Remove(from);
|
|
|
|
}
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
DeleteEventInternal(CODE_DELETE_EVENT, from);
|
|
|
|
}
|
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
|
|
|
|
int pc_offset,
|
|
|
|
int position) {
|
|
|
|
if (code_event_handler_ != NULL) {
|
|
|
|
IssueAddCodeLinePosInfoEvent(jit_handler_data,
|
|
|
|
pc_offset,
|
|
|
|
position,
|
|
|
|
JitCodeEvent::POSITION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
|
|
|
|
int pc_offset,
|
|
|
|
int position) {
|
|
|
|
if (code_event_handler_ != NULL) {
|
|
|
|
IssueAddCodeLinePosInfoEvent(jit_handler_data,
|
|
|
|
pc_offset,
|
|
|
|
position,
|
|
|
|
JitCodeEvent::STATEMENT_POSITION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
|
|
|
|
if (code_event_handler_ != NULL) {
|
|
|
|
pos_recorder->AttachJITHandlerData(IssueStartCodePosInfoEvent());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
|
|
|
|
void* jit_handler_data) {
|
|
|
|
if (code_event_handler_ != NULL) {
|
|
|
|
IssueEndCodePosInfoEvent(code, jit_handler_data);
|
|
|
|
}
|
|
|
|
}
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
|
|
|
|
void Logger::SnapshotPositionEvent(Address addr, int pos) {
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
|
|
|
if (FLAG_ll_prof) LowLevelSnapshotPositionEvent(addr, pos);
|
|
|
|
if (Serializer::enabled() && address_to_name_map_ != NULL) {
|
|
|
|
const char* code_name = address_to_name_map_->Lookup(addr);
|
|
|
|
if (code_name == NULL) return; // Not a code object.
|
|
|
|
LogMessageBuilder msg(this);
|
|
|
|
msg.Append("%s,%d,\"", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
|
|
|
|
for (const char* p = code_name; *p != '\0'; ++p) {
|
|
|
|
if (*p == '"') msg.Append('\\');
|
|
|
|
msg.Append(*p);
|
|
|
|
}
|
|
|
|
msg.Append("\"\n");
|
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
if (!FLAG_log_snapshot_positions) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
msg.AppendAddress(addr);
|
|
|
|
msg.Append(",%d", pos);
|
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-10 12:00:27 +00:00
|
|
|
void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
|
|
|
|
MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::MoveEventInternal(LogEventsAndTags event,
|
|
|
|
Address from,
|
|
|
|
Address to) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.Append("%s,", kLogEventsNames[event]);
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.AppendAddress(from);
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
msg.Append(',');
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.AppendAddress(to);
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.Append('\n');
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-12-19 13:12:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-27 17:10:28 +00:00
|
|
|
void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.Append("%s,", kLogEventsNames[event]);
|
Fix issue 553: function frame is skipped in profile when compare stub is called.
The problem appeared due to a fact that stubs doesn't create a stack
frame, reusing the stack frame of the caller function. When building
stack traces, the current function is retrieved from PC, and its
callees are retrieved by traversing the stack backwards. Thus, for
stubs, the stub itself was discovered via PC, and then stub's caller's
caller was retrieved from stack.
To fix this problem, a pointer to JSFunction object is now captured
from the topmost stack frame, and is saved into stack trace log
record. Then a simple heuristics is applied whether a referred
function should be added to decoded stack, or not, to avoid reporting
the same function twice (from PC and from the pointer.)
BUG=553
TEST=added to mjsunit/tools/tickprocessor
Review URL: http://codereview.chromium.org/546089
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2010-01-21 16:42:41 +00:00
|
|
|
msg.AppendAddress(from);
|
2010-01-18 16:04:25 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::ResourceEvent(const char* name, const char* tag) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("%s,%s,", name, tag);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
uint32_t sec, usec;
|
|
|
|
if (OS::GetUserTime(&sec, &usec) != -1) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("%d,%d,", sec, usec);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("%.0f", OS::TimeCurrentMillis());
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 15:00:57 +00:00
|
|
|
void Logger::SuspectReadEvent(Name* name, Object* obj) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_suspect) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2008-12-09 09:19:02 +00:00
|
|
|
String* class_name = obj->IsJSObject()
|
|
|
|
? JSObject::cast(obj)->class_name()
|
2013-02-15 09:27:10 +00:00
|
|
|
: isolate_->heap()->empty_string();
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("suspect-read,");
|
|
|
|
msg.Append(class_name);
|
|
|
|
msg.Append(',');
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
msg.Append('"');
|
|
|
|
msg.Append(String::cast(name));
|
|
|
|
msg.Append('"');
|
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
msg.Append("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
msg.Append("\"");
|
|
|
|
msg.AppendDetailed(String::cast(symbol->name()), false);
|
|
|
|
msg.Append("\" ");
|
|
|
|
}
|
|
|
|
msg.Append("hash %x)", symbol->Hash());
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_gc) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-07-20 09:38:44 +00:00
|
|
|
// Using non-relative system time in order to be able to synchronize with
|
|
|
|
// external memory profiling events (e.g. DOM memory size).
|
|
|
|
msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
|
|
|
|
space, kind, OS::TimeCurrentMillis());
|
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_gc) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log_gc) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-06 10:02:49 +00:00
|
|
|
void Logger::DebugTag(const char* call_site_tag) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("debug-tag,%s\n", call_site_tag);
|
|
|
|
msg.WriteToLogFile();
|
2008-08-06 10:02:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_log) return;
|
2008-08-06 10:02:49 +00:00
|
|
|
StringBuilder s(parameter.length() + 1);
|
|
|
|
for (int i = 0; i < parameter.length(); ++i) {
|
|
|
|
s.AddCharacter(static_cast<char>(parameter[i]));
|
|
|
|
}
|
|
|
|
char* parameter_string = s.Finalize();
|
2011-03-18 20:35:07 +00:00
|
|
|
LogMessageBuilder msg(this);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("debug-queue-event,%s,%15.3f,%s\n",
|
|
|
|
event_type,
|
|
|
|
OS::TimeCurrentMillis(),
|
|
|
|
parameter_string);
|
2008-08-06 10:02:49 +00:00
|
|
|
DeleteArray(parameter_string);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-08-06 10:02:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void Logger::TickEvent(TickSample* sample, bool overflow) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_prof) return;
|
|
|
|
LogMessageBuilder msg(this);
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
|
|
|
|
msg.AppendAddress(sample->pc);
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.Append(',');
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.AppendAddress(sample->sp);
|
2012-12-05 16:22:14 +00:00
|
|
|
msg.Append(",%ld", static_cast<int>(OS::Ticks() - epoch_));
|
2013-04-19 11:55:01 +00:00
|
|
|
if (sample->has_external_callback) {
|
|
|
|
msg.Append(",1,");
|
|
|
|
msg.AppendAddress(sample->external_callback);
|
|
|
|
} else {
|
|
|
|
msg.Append(",0,");
|
|
|
|
msg.AppendAddress(sample->tos);
|
|
|
|
}
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.Append(",%d", static_cast<int>(sample->state));
|
2009-02-17 12:49:35 +00:00
|
|
|
if (overflow) {
|
|
|
|
msg.Append(",overflow");
|
|
|
|
}
|
2009-03-06 13:07:57 +00:00
|
|
|
for (int i = 0; i < sample->frames_count; ++i) {
|
2009-06-15 09:37:50 +00:00
|
|
|
msg.Append(',');
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.AppendAddress(sample->stack[i]);
|
2009-06-11 14:08:34 +00:00
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('\n');
|
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2009-01-29 19:47:00 +00:00
|
|
|
|
|
|
|
|
2011-07-01 09:35:16 +00:00
|
|
|
bool Logger::IsProfilerPaused() {
|
|
|
|
return profiler_ == NULL || profiler_->paused();
|
2009-01-29 19:47:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-01 09:35:16 +00:00
|
|
|
void Logger::PauseProfiler() {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
2011-07-01 09:35:16 +00:00
|
|
|
if (profiler_ != NULL) {
|
2010-02-17 13:23:46 +00:00
|
|
|
// It is OK to have negative nesting.
|
|
|
|
if (--cpu_profiler_nesting_ == 0) {
|
|
|
|
profiler_->pause();
|
|
|
|
if (FLAG_prof_lazy) {
|
2012-12-07 13:47:42 +00:00
|
|
|
ticker_->Stop();
|
2010-02-17 13:23:46 +00:00
|
|
|
FLAG_log_code = false;
|
2011-03-18 20:35:07 +00:00
|
|
|
LOG(ISOLATE, UncheckedStringEvent("profiler", "pause"));
|
2010-02-17 13:23:46 +00:00
|
|
|
}
|
2010-03-01 10:41:34 +00:00
|
|
|
--logging_nesting_;
|
2009-08-04 14:14:01 +00:00
|
|
|
}
|
2009-05-29 06:56:23 +00:00
|
|
|
}
|
2009-01-29 19:47:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-01 09:35:16 +00:00
|
|
|
void Logger::ResumeProfiler() {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
2011-07-01 09:35:16 +00:00
|
|
|
if (profiler_ != NULL) {
|
2010-02-17 13:23:46 +00:00
|
|
|
if (cpu_profiler_nesting_++ == 0) {
|
2010-03-01 10:41:34 +00:00
|
|
|
++logging_nesting_;
|
2010-02-17 13:23:46 +00:00
|
|
|
if (FLAG_prof_lazy) {
|
|
|
|
profiler_->Engage();
|
2011-03-18 20:35:07 +00:00
|
|
|
LOG(ISOLATE, UncheckedStringEvent("profiler", "resume"));
|
2010-02-17 13:23:46 +00:00
|
|
|
FLAG_log_code = true;
|
|
|
|
LogCompiledFunctions();
|
|
|
|
LogAccessorCallbacks();
|
2012-12-07 13:47:42 +00:00
|
|
|
if (!ticker_->IsActive()) ticker_->Start();
|
2010-02-17 13:23:46 +00:00
|
|
|
}
|
|
|
|
profiler_->resume();
|
2009-08-04 14:14:01 +00:00
|
|
|
}
|
2009-05-29 06:56:23 +00:00
|
|
|
}
|
2009-01-29 19:47:00 +00:00
|
|
|
}
|
2009-05-05 15:57:47 +00:00
|
|
|
|
|
|
|
|
2009-05-28 13:56:32 +00:00
|
|
|
// This function can be called when Log's mutex is acquired,
|
|
|
|
// either from main or Profiler's thread.
|
2011-03-18 20:35:07 +00:00
|
|
|
void Logger::LogFailure() {
|
2011-07-01 09:35:16 +00:00
|
|
|
PauseProfiler();
|
2009-05-28 13:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
|
|
|
|
public:
|
|
|
|
EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
|
|
|
|
Handle<Code>* code_objects,
|
|
|
|
int* count)
|
|
|
|
: sfis_(sfis), code_objects_(code_objects), count_(count) { }
|
|
|
|
|
|
|
|
virtual void EnterContext(Context* context) {}
|
|
|
|
virtual void LeaveContext(Context* context) {}
|
|
|
|
|
|
|
|
virtual void VisitFunction(JSFunction* function) {
|
2011-06-17 08:40:30 +00:00
|
|
|
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
|
|
|
|
Object* maybe_script = sfi->script();
|
|
|
|
if (maybe_script->IsScript()
|
|
|
|
&& !Script::cast(maybe_script)->HasValidSource()) return;
|
2010-12-07 11:31:57 +00:00
|
|
|
if (sfis_ != NULL) {
|
2011-06-17 08:40:30 +00:00
|
|
|
sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
if (code_objects_ != NULL) {
|
|
|
|
ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
|
|
|
|
code_objects_[*count_] = Handle<Code>(function->code());
|
|
|
|
}
|
|
|
|
*count_ = *count_ + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<SharedFunctionInfo>* sfis_;
|
|
|
|
Handle<Code>* code_objects_;
|
|
|
|
int* count_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-02-11 13:02:20 +00:00
|
|
|
static int EnumerateCompiledFunctions(Heap* heap,
|
|
|
|
Handle<SharedFunctionInfo>* sfis,
|
2010-12-07 11:31:57 +00:00
|
|
|
Handle<Code>* code_objects) {
|
2013-02-11 13:02:20 +00:00
|
|
|
HeapIterator iterator(heap);
|
2013-06-03 15:32:22 +00:00
|
|
|
DisallowHeapAllocation no_gc;
|
2009-05-20 09:04:13 +00:00
|
|
|
int compiled_funcs_count = 0;
|
2010-12-07 11:31:57 +00:00
|
|
|
|
|
|
|
// Iterate the heap to find shared function info objects and record
|
|
|
|
// the unoptimized code for them.
|
2010-01-25 22:53:18 +00:00
|
|
|
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
|
2009-10-07 12:20:02 +00:00
|
|
|
if (!obj->IsSharedFunctionInfo()) continue;
|
|
|
|
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
|
|
|
|
if (sfi->is_compiled()
|
|
|
|
&& (!sfi->script()->IsScript()
|
|
|
|
|| Script::cast(sfi->script())->HasValidSource())) {
|
2010-12-07 11:31:57 +00:00
|
|
|
if (sfis != NULL) {
|
2009-10-07 12:20:02 +00:00
|
|
|
sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
if (code_objects != NULL) {
|
|
|
|
code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
|
|
|
|
}
|
2009-10-07 12:20:02 +00:00
|
|
|
++compiled_funcs_count;
|
2009-05-20 09:04:13 +00:00
|
|
|
}
|
2009-10-07 12:20:02 +00:00
|
|
|
}
|
2010-12-07 11:31:57 +00:00
|
|
|
|
|
|
|
// Iterate all optimized functions in all contexts.
|
|
|
|
EnumerateOptimizedFunctionsVisitor visitor(sfis,
|
|
|
|
code_objects,
|
|
|
|
&compiled_funcs_count);
|
2013-03-18 13:57:49 +00:00
|
|
|
Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
|
2010-12-07 11:31:57 +00:00
|
|
|
|
2009-10-07 12:20:02 +00:00
|
|
|
return compiled_funcs_count;
|
|
|
|
}
|
2009-05-20 09:04:13 +00:00
|
|
|
|
|
|
|
|
2009-11-11 12:35:50 +00:00
|
|
|
void Logger::LogCodeObject(Object* object) {
|
2013-06-03 09:46:32 +00:00
|
|
|
Code* code_object = Code::cast(object);
|
|
|
|
LogEventsAndTags tag = Logger::STUB_TAG;
|
|
|
|
const char* description = "Unknown code from the snapshot";
|
|
|
|
switch (code_object->kind()) {
|
|
|
|
case Code::FUNCTION:
|
|
|
|
case Code::OPTIMIZED_FUNCTION:
|
|
|
|
return; // We log this later using LogCompiledFunctions.
|
|
|
|
case Code::UNARY_OP_IC: // fall through
|
|
|
|
case Code::BINARY_OP_IC: // fall through
|
|
|
|
case Code::COMPARE_IC: // fall through
|
|
|
|
case Code::COMPARE_NIL_IC: // fall through
|
|
|
|
case Code::TO_BOOLEAN_IC: // fall through
|
|
|
|
case Code::STUB:
|
|
|
|
description =
|
|
|
|
CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
|
|
|
|
if (description == NULL)
|
|
|
|
description = "A stub from the snapshot";
|
|
|
|
tag = Logger::STUB_TAG;
|
|
|
|
break;
|
|
|
|
case Code::BUILTIN:
|
|
|
|
description = "A builtin from the snapshot";
|
|
|
|
tag = Logger::BUILTIN_TAG;
|
|
|
|
break;
|
|
|
|
case Code::KEYED_LOAD_IC:
|
|
|
|
description = "A keyed load IC from the snapshot";
|
|
|
|
tag = Logger::KEYED_LOAD_IC_TAG;
|
|
|
|
break;
|
|
|
|
case Code::LOAD_IC:
|
|
|
|
description = "A load IC from the snapshot";
|
|
|
|
tag = Logger::LOAD_IC_TAG;
|
|
|
|
break;
|
|
|
|
case Code::STORE_IC:
|
|
|
|
description = "A store IC from the snapshot";
|
|
|
|
tag = Logger::STORE_IC_TAG;
|
|
|
|
break;
|
|
|
|
case Code::KEYED_STORE_IC:
|
|
|
|
description = "A keyed store IC from the snapshot";
|
|
|
|
tag = Logger::KEYED_STORE_IC_TAG;
|
|
|
|
break;
|
|
|
|
case Code::CALL_IC:
|
|
|
|
description = "A call IC from the snapshot";
|
|
|
|
tag = Logger::CALL_IC_TAG;
|
|
|
|
break;
|
|
|
|
case Code::KEYED_CALL_IC:
|
|
|
|
description = "A keyed call IC from the snapshot";
|
|
|
|
tag = Logger::KEYED_CALL_IC_TAG;
|
|
|
|
break;
|
2009-11-11 12:35:50 +00:00
|
|
|
}
|
2013-06-03 09:46:32 +00:00
|
|
|
PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
|
2009-11-11 12:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-19 16:45:11 +00:00
|
|
|
void Logger::LogCodeInfo() {
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_ll_prof) return;
|
2010-10-19 16:45:11 +00:00
|
|
|
#if V8_TARGET_ARCH_IA32
|
|
|
|
const char arch[] = "ia32";
|
|
|
|
#elif V8_TARGET_ARCH_X64
|
|
|
|
const char arch[] = "x64";
|
|
|
|
#elif V8_TARGET_ARCH_ARM
|
|
|
|
const char arch[] = "arm";
|
2011-11-09 18:36:31 +00:00
|
|
|
#elif V8_TARGET_ARCH_MIPS
|
|
|
|
const char arch[] = "mips";
|
2010-10-19 16:45:11 +00:00
|
|
|
#else
|
|
|
|
const char arch[] = "unknown";
|
|
|
|
#endif
|
2011-04-29 16:06:25 +00:00
|
|
|
LowLevelLogWriteBytes(arch, sizeof(arch));
|
2010-10-19 16:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-29 16:06:25 +00:00
|
|
|
void Logger::RegisterSnapshotCodeName(Code* code,
|
|
|
|
const char* name,
|
|
|
|
int name_size) {
|
|
|
|
ASSERT(Serializer::enabled());
|
|
|
|
if (address_to_name_map_ == NULL) {
|
|
|
|
address_to_name_map_ = new NameMap;
|
|
|
|
}
|
|
|
|
address_to_name_map_->Insert(code->address(), name, name_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::LowLevelCodeCreateEvent(Code* code,
|
|
|
|
const char* name,
|
|
|
|
int name_size) {
|
|
|
|
if (log_->ll_output_handle_ == NULL) return;
|
|
|
|
LowLevelCodeCreateStruct event;
|
|
|
|
event.name_size = name_size;
|
|
|
|
event.code_address = code->instruction_start();
|
|
|
|
ASSERT(event.code_address == code->address() + Code::kHeaderSize);
|
|
|
|
event.code_size = code->instruction_size();
|
|
|
|
LowLevelLogWriteStruct(event);
|
|
|
|
LowLevelLogWriteBytes(name, name_size);
|
|
|
|
LowLevelLogWriteBytes(
|
|
|
|
reinterpret_cast<const char*>(code->instruction_start()),
|
|
|
|
code->instruction_size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::LowLevelCodeMoveEvent(Address from, Address to) {
|
|
|
|
if (log_->ll_output_handle_ == NULL) return;
|
|
|
|
LowLevelCodeMoveStruct event;
|
|
|
|
event.from_address = from + Code::kHeaderSize;
|
|
|
|
event.to_address = to + Code::kHeaderSize;
|
|
|
|
LowLevelLogWriteStruct(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::LowLevelCodeDeleteEvent(Address from) {
|
|
|
|
if (log_->ll_output_handle_ == NULL) return;
|
|
|
|
LowLevelCodeDeleteStruct event;
|
|
|
|
event.address = from + Code::kHeaderSize;
|
|
|
|
LowLevelLogWriteStruct(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::LowLevelSnapshotPositionEvent(Address addr, int pos) {
|
|
|
|
if (log_->ll_output_handle_ == NULL) return;
|
|
|
|
LowLevelSnapshotPositionStruct event;
|
|
|
|
event.address = addr + Code::kHeaderSize;
|
|
|
|
event.position = pos;
|
|
|
|
LowLevelLogWriteStruct(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::LowLevelLogWriteBytes(const char* bytes, int size) {
|
|
|
|
size_t rv = fwrite(bytes, 1, size, log_->ll_output_handle_);
|
|
|
|
ASSERT(static_cast<size_t>(size) == rv);
|
2010-10-25 08:22:23 +00:00
|
|
|
USE(rv);
|
2010-10-19 16:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-04 21:34:03 +00:00
|
|
|
void Logger::LogCodeObjects() {
|
2013-02-15 09:27:10 +00:00
|
|
|
Heap* heap = isolate_->heap();
|
2013-02-11 13:02:20 +00:00
|
|
|
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
|
2012-02-03 14:16:40 +00:00
|
|
|
"Logger::LogCodeObjects");
|
2013-02-11 13:02:20 +00:00
|
|
|
HeapIterator iterator(heap);
|
2013-06-03 15:32:22 +00:00
|
|
|
DisallowHeapAllocation no_gc;
|
2010-02-04 21:34:03 +00:00
|
|
|
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
|
|
|
|
if (obj->IsCode()) LogCodeObject(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-14 11:47:03 +00:00
|
|
|
void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
|
|
|
|
Handle<Code> code) {
|
|
|
|
Handle<String> func_name(shared->DebugName());
|
|
|
|
if (shared->script()->IsScript()) {
|
|
|
|
Handle<Script> script(Script::cast(shared->script()));
|
2013-06-12 08:27:24 +00:00
|
|
|
Handle<String> script_name;
|
2011-09-14 11:47:03 +00:00
|
|
|
if (script->name()->IsString()) {
|
2013-06-12 08:27:24 +00:00
|
|
|
script_name = Handle<String>(String::cast(script->name()));
|
|
|
|
} else {
|
|
|
|
Handle<Object> name = GetScriptNameOrSourceURL(script);
|
|
|
|
if (!name.is_null() && name->IsString()) {
|
|
|
|
script_name = Handle<String>::cast(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!script_name.is_null()) {
|
2011-09-14 11:47:03 +00:00
|
|
|
int line_num = GetScriptLineNumber(script, shared->start_position());
|
2013-06-12 08:27:24 +00:00
|
|
|
if (line_num > -1) {
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_,
|
2011-09-14 11:47:03 +00:00
|
|
|
CodeCreateEvent(
|
|
|
|
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
|
2013-05-14 22:51:33 +00:00
|
|
|
*code, *shared, NULL,
|
2011-09-14 11:47:03 +00:00
|
|
|
*script_name, line_num + 1));
|
|
|
|
} else {
|
|
|
|
// Can't distinguish eval and script here, so always use Script.
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_,
|
2011-09-14 11:47:03 +00:00
|
|
|
CodeCreateEvent(
|
|
|
|
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
|
2013-05-14 22:51:33 +00:00
|
|
|
*code, *shared, NULL, *script_name));
|
2011-09-14 11:47:03 +00:00
|
|
|
}
|
|
|
|
} else {
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_,
|
2011-09-14 11:47:03 +00:00
|
|
|
CodeCreateEvent(
|
|
|
|
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
|
2013-05-14 22:51:33 +00:00
|
|
|
*code, *shared, NULL, *func_name));
|
2011-09-14 11:47:03 +00:00
|
|
|
}
|
|
|
|
} else if (shared->IsApiFunction()) {
|
|
|
|
// API function.
|
|
|
|
FunctionTemplateInfo* fun_data = shared->get_api_func_data();
|
|
|
|
Object* raw_call_data = fun_data->call_code();
|
|
|
|
if (!raw_call_data->IsUndefined()) {
|
|
|
|
CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
|
|
|
|
Object* callback_obj = call_data->callback();
|
|
|
|
Address entry_point = v8::ToCData<Address>(callback_obj);
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
|
2011-09-14 11:47:03 +00:00
|
|
|
}
|
|
|
|
} else {
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_,
|
2011-09-14 11:47:03 +00:00
|
|
|
CodeCreateEvent(
|
2013-05-14 22:51:33 +00:00
|
|
|
Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
|
2011-09-14 11:47:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-07 12:20:02 +00:00
|
|
|
void Logger::LogCompiledFunctions() {
|
2013-02-15 09:27:10 +00:00
|
|
|
Heap* heap = isolate_->heap();
|
2013-02-11 13:02:20 +00:00
|
|
|
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
|
2012-02-03 14:16:40 +00:00
|
|
|
"Logger::LogCompiledFunctions");
|
2013-02-15 09:27:10 +00:00
|
|
|
HandleScope scope(isolate_);
|
2013-02-11 13:02:20 +00:00
|
|
|
const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
|
2010-05-05 12:25:58 +00:00
|
|
|
ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
|
2010-12-07 11:31:57 +00:00
|
|
|
ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
|
2013-02-11 13:02:20 +00:00
|
|
|
EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
|
2009-05-20 09:04:13 +00:00
|
|
|
|
|
|
|
// During iteration, there can be heap allocation due to
|
|
|
|
// GetScriptLineNumber call.
|
|
|
|
for (int i = 0; i < compiled_funcs_count; ++i) {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
|
2011-03-23 13:40:07 +00:00
|
|
|
Builtins::kLazyCompile))
|
2011-03-18 20:35:07 +00:00
|
|
|
continue;
|
2011-09-14 11:47:03 +00:00
|
|
|
LogExistingFunction(sfis[i], code_objects[i]);
|
2009-05-20 09:04:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-25 16:39:18 +00:00
|
|
|
|
|
|
|
void Logger::LogAccessorCallbacks() {
|
2013-02-15 09:27:10 +00:00
|
|
|
Heap* heap = isolate_->heap();
|
2013-02-11 13:02:20 +00:00
|
|
|
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
|
2012-02-03 14:16:40 +00:00
|
|
|
"Logger::LogAccessorCallbacks");
|
2013-02-11 13:02:20 +00:00
|
|
|
HeapIterator iterator(heap);
|
2013-06-03 15:32:22 +00:00
|
|
|
DisallowHeapAllocation no_gc;
|
2010-01-25 22:53:18 +00:00
|
|
|
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
|
2013-02-12 14:33:08 +00:00
|
|
|
if (!obj->IsExecutableAccessorInfo()) continue;
|
|
|
|
ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
|
2013-03-04 15:00:57 +00:00
|
|
|
if (!ai->name()->IsName()) continue;
|
2009-11-25 16:39:18 +00:00
|
|
|
Address getter_entry = v8::ToCData<Address>(ai->getter());
|
2013-03-04 15:00:57 +00:00
|
|
|
Name* name = Name::cast(ai->name());
|
2009-11-25 16:39:18 +00:00
|
|
|
if (getter_entry != 0) {
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
|
2009-11-25 16:39:18 +00:00
|
|
|
}
|
|
|
|
Address setter_entry = v8::ToCData<Address>(ai->setter());
|
|
|
|
if (setter_entry != 0) {
|
2013-04-02 07:53:50 +00:00
|
|
|
PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
|
2009-11-25 16:39:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2013-04-24 14:44:08 +00:00
|
|
|
bool Logger::SetUp(Isolate* isolate) {
|
2011-03-18 20:35:07 +00:00
|
|
|
// Tests and EnsureInitialize() can call this twice in a row. It's harmless.
|
|
|
|
if (is_initialized_) return true;
|
|
|
|
is_initialized_ = true;
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2010-10-19 16:45:11 +00:00
|
|
|
// --ll-prof implies --log-code and --log-snapshot-positions.
|
|
|
|
if (FLAG_ll_prof) {
|
|
|
|
FLAG_log_snapshot_positions = true;
|
|
|
|
}
|
|
|
|
|
2009-05-25 08:25:36 +00:00
|
|
|
// --prof_lazy controls --log-code, implies --noprof_auto.
|
|
|
|
if (FLAG_prof_lazy) {
|
|
|
|
FLAG_log_code = false;
|
|
|
|
FLAG_prof_auto = false;
|
|
|
|
}
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
log_->Initialize();
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2010-10-19 16:45:11 +00:00
|
|
|
if (FLAG_ll_prof) LogCodeInfo();
|
|
|
|
|
2011-06-10 09:54:04 +00:00
|
|
|
ticker_ = new Ticker(isolate, kSamplingIntervalMs);
|
|
|
|
|
2013-04-24 14:44:08 +00:00
|
|
|
if (Log::InitLogAtStart()) {
|
2010-03-01 10:41:34 +00:00
|
|
|
logging_nesting_ = 1;
|
|
|
|
}
|
2009-06-24 13:09:34 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
if (FLAG_prof) {
|
2011-06-10 09:42:08 +00:00
|
|
|
profiler_ = new Profiler(isolate);
|
2009-06-24 13:09:34 +00:00
|
|
|
if (!FLAG_prof_auto) {
|
2009-01-29 19:47:00 +00:00
|
|
|
profiler_->pause();
|
2009-06-24 13:09:34 +00:00
|
|
|
} else {
|
2010-03-01 10:41:34 +00:00
|
|
|
logging_nesting_ = 1;
|
2009-06-24 13:09:34 +00:00
|
|
|
}
|
2009-10-28 09:13:11 +00:00
|
|
|
if (!FLAG_prof_lazy) {
|
|
|
|
profiler_->Engage();
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 16:22:14 +00:00
|
|
|
if (FLAG_log_internal_timer_events || FLAG_prof) epoch_ = OS::Ticks();
|
2012-11-22 13:04:11 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-28 14:43:28 +00:00
|
|
|
void Logger::SetCodeEventHandler(uint32_t options,
|
|
|
|
JitCodeEventHandler event_handler) {
|
|
|
|
code_event_handler_ = event_handler;
|
|
|
|
|
|
|
|
if (code_event_handler_ != NULL && (options & kJitCodeEventEnumExisting)) {
|
2013-02-15 09:27:10 +00:00
|
|
|
HandleScope scope(Isolate::Current());
|
2012-08-28 14:43:28 +00:00
|
|
|
LogCodeObjects();
|
|
|
|
LogCompiledFunctions();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
Sampler* Logger::sampler() {
|
|
|
|
return ticker_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-13 11:31:22 +00:00
|
|
|
FILE* Logger::TearDown() {
|
|
|
|
if (!is_initialized_) return NULL;
|
2011-03-18 20:35:07 +00:00
|
|
|
is_initialized_ = false;
|
2009-05-28 13:56:32 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// Stop the profiler before closing the file.
|
|
|
|
if (profiler_ != NULL) {
|
|
|
|
profiler_->Disengage();
|
|
|
|
delete profiler_;
|
|
|
|
profiler_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete ticker_;
|
2009-05-25 08:25:36 +00:00
|
|
|
ticker_ = NULL;
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2011-07-13 11:31:22 +00:00
|
|
|
return log_->Close();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|