2011-05-18 13:17:29 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2014-04-29 06:42:26 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2014-09-30 10:29:32 +00:00
|
|
|
#include "src/log.h"
|
|
|
|
|
|
|
|
#include <cstdarg>
|
|
|
|
#include <sstream>
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/v8.h"
|
|
|
|
|
2014-09-24 07:08:27 +00:00
|
|
|
#include "src/bailout-reason.h"
|
2014-06-30 13:25:46 +00:00
|
|
|
#include "src/base/platform/platform.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/bootstrapper.h"
|
|
|
|
#include "src/code-stubs.h"
|
|
|
|
#include "src/cpu-profiler.h"
|
|
|
|
#include "src/deoptimizer.h"
|
|
|
|
#include "src/global-handles.h"
|
2014-10-14 14:45:03 +00:00
|
|
|
#include "src/log-inl.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/log-utils.h"
|
|
|
|
#include "src/macro-assembler.h"
|
2014-07-03 19:18:26 +00:00
|
|
|
#include "src/perf-jit.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/runtime-profiler.h"
|
|
|
|
#include "src/serialize.h"
|
|
|
|
#include "src/string-stream.h"
|
|
|
|
#include "src/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
|
|
|
|
2013-07-15 11:35:39 +00:00
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
#define DECLARE_EVENT(ignore1, name) name,
|
|
|
|
static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
|
|
|
|
LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
|
|
|
|
};
|
|
|
|
#undef DECLARE_EVENT
|
|
|
|
|
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
#define CALL_LISTENERS(Call) \
|
|
|
|
for (int i = 0; i < listeners_.length(); ++i) { \
|
|
|
|
listeners_[i]->Call; \
|
|
|
|
}
|
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
#define PROFILER_LOG(Call) \
|
|
|
|
do { \
|
|
|
|
CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
|
|
|
|
if (cpu_profiler->is_profiling()) { \
|
|
|
|
cpu_profiler->Call; \
|
|
|
|
} \
|
|
|
|
} while (false);
|
|
|
|
|
2013-07-19 15:57:18 +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 "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
class CodeEventLogger::NameBuffer {
|
2013-07-19 14:58:53 +00:00
|
|
|
public:
|
2013-07-26 13:50:23 +00:00
|
|
|
NameBuffer() { Reset(); }
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void Reset() {
|
|
|
|
utf8_pos_ = 0;
|
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void Init(Logger::LogEventsAndTags tag) {
|
|
|
|
Reset();
|
|
|
|
AppendBytes(kLogEventsNames[tag]);
|
|
|
|
AppendByte(':');
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppendName(Name* name) {
|
|
|
|
if (name->IsString()) {
|
|
|
|
AppendString(String::cast(name));
|
|
|
|
} else {
|
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
AppendBytes("symbol(");
|
|
|
|
if (!symbol->name()->IsUndefined()) {
|
|
|
|
AppendBytes("\"");
|
|
|
|
AppendString(String::cast(symbol->name()));
|
|
|
|
AppendBytes("\" ");
|
2013-07-19 14:58:53 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
AppendBytes("hash ");
|
|
|
|
AppendHex(symbol->Hash());
|
|
|
|
AppendByte(')');
|
2013-07-19 14:58:53 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void AppendString(String* str) {
|
|
|
|
if (str == NULL) return;
|
|
|
|
int uc16_length = Min(str->length(), kUtf16BufferSize);
|
|
|
|
String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
|
|
|
|
int previous = unibrow::Utf16::kNoPreviousCharacter;
|
|
|
|
for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
|
|
|
|
uc16 c = utf16_buffer[i];
|
|
|
|
if (c <= unibrow::Utf8::kMaxOneByteChar) {
|
|
|
|
utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
|
|
|
|
} else {
|
|
|
|
int char_length = unibrow::Utf8::Length(c, previous);
|
|
|
|
if (utf8_pos_ + char_length > kUtf8BufferSize) break;
|
|
|
|
unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
|
|
|
|
utf8_pos_ += char_length;
|
2013-07-19 14:58:53 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
previous = c;
|
2013-07-19 14:58:53 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void AppendBytes(const char* bytes, int size) {
|
|
|
|
size = Min(size, kUtf8BufferSize - utf8_pos_);
|
2014-05-27 07:57:22 +00:00
|
|
|
MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
|
2013-07-26 13:50:23 +00:00
|
|
|
utf8_pos_ += size;
|
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void AppendBytes(const char* bytes) {
|
|
|
|
AppendBytes(bytes, StrLength(bytes));
|
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void AppendByte(char c) {
|
|
|
|
if (utf8_pos_ >= kUtf8BufferSize) return;
|
|
|
|
utf8_buffer_[utf8_pos_++] = c;
|
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void AppendInt(int n) {
|
|
|
|
Vector<char> buffer(utf8_buffer_ + utf8_pos_,
|
|
|
|
kUtf8BufferSize - utf8_pos_);
|
2014-06-13 16:43:27 +00:00
|
|
|
int size = SNPrintF(buffer, "%d", n);
|
2013-07-26 13:50:23 +00:00
|
|
|
if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
|
|
|
|
utf8_pos_ += size;
|
2013-07-19 14:58:53 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void AppendHex(uint32_t n) {
|
|
|
|
Vector<char> buffer(utf8_buffer_ + utf8_pos_,
|
|
|
|
kUtf8BufferSize - utf8_pos_);
|
2014-06-13 16:43:27 +00:00
|
|
|
int size = SNPrintF(buffer, "%x", n);
|
2013-07-26 13:50:23 +00:00
|
|
|
if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
|
|
|
|
utf8_pos_ += size;
|
2013-07-19 14:58:53 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
}
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
const char* get() { return utf8_buffer_; }
|
|
|
|
int size() const { return utf8_pos_; }
|
2013-07-19 14:58:53 +00:00
|
|
|
|
|
|
|
private:
|
2013-07-26 13:50:23 +00:00
|
|
|
static const int kUtf8BufferSize = 512;
|
|
|
|
static const int kUtf16BufferSize = 128;
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
int utf8_pos_;
|
|
|
|
char utf8_buffer_[kUtf8BufferSize];
|
|
|
|
uc16 utf16_buffer[kUtf16BufferSize];
|
2013-07-19 14:58:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
|
|
|
|
|
|
|
|
CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
|
|
|
|
|
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
const char* comment) {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->Init(tag);
|
|
|
|
name_buffer_->AppendBytes(comment);
|
|
|
|
LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
Name* name) {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->Init(tag);
|
|
|
|
name_buffer_->AppendName(name);
|
|
|
|
LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
2013-07-26 13:50:23 +00:00
|
|
|
Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
|
|
|
CompilationInfo* info,
|
|
|
|
Name* name) {
|
|
|
|
name_buffer_->Init(tag);
|
|
|
|
name_buffer_->AppendBytes(ComputeMarker(code));
|
|
|
|
name_buffer_->AppendName(name);
|
|
|
|
LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
2013-07-26 13:50:23 +00:00
|
|
|
Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
|
|
|
CompilationInfo* info,
|
2013-10-10 13:15:47 +00:00
|
|
|
Name* source, int line, int column) {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->Init(tag);
|
|
|
|
name_buffer_->AppendBytes(ComputeMarker(code));
|
|
|
|
name_buffer_->AppendString(shared->DebugName());
|
|
|
|
name_buffer_->AppendByte(' ');
|
2013-07-19 15:57:18 +00:00
|
|
|
if (source->IsString()) {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->AppendString(String::cast(source));
|
2013-07-19 15:57:18 +00:00
|
|
|
} else {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->AppendBytes("symbol(hash ");
|
|
|
|
name_buffer_->AppendHex(Name::cast(source)->Hash());
|
|
|
|
name_buffer_->AppendByte(')');
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->AppendByte(':');
|
|
|
|
name_buffer_->AppendInt(line);
|
|
|
|
LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
int args_count) {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->Init(tag);
|
|
|
|
name_buffer_->AppendInt(args_count);
|
|
|
|
LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
|
2013-07-26 13:50:23 +00:00
|
|
|
name_buffer_->Init(Logger::REG_EXP_TAG);
|
|
|
|
name_buffer_->AppendString(source);
|
|
|
|
LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 06:44:23 +00:00
|
|
|
// Linux perf tool logging support
|
|
|
|
class PerfBasicLogger : public CodeEventLogger {
|
|
|
|
public:
|
|
|
|
PerfBasicLogger();
|
|
|
|
virtual ~PerfBasicLogger();
|
|
|
|
|
|
|
|
virtual void CodeMoveEvent(Address from, Address to) { }
|
2014-05-22 05:36:27 +00:00
|
|
|
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
2013-11-25 06:44:23 +00:00
|
|
|
virtual void CodeDeleteEvent(Address from) { }
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void LogRecordedBuffer(Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
|
|
|
const char* name,
|
|
|
|
int length);
|
|
|
|
|
|
|
|
// Extension added to V8 log file name to get the low-level log name.
|
|
|
|
static const char kFilenameFormatString[];
|
|
|
|
static const int kFilenameBufferPadding;
|
|
|
|
|
|
|
|
// File buffer size of the low-level log. We don't use the default to
|
|
|
|
// minimize the associated overhead.
|
|
|
|
static const int kLogBufferSize = 2 * MB;
|
|
|
|
|
|
|
|
FILE* perf_output_handle_;
|
|
|
|
};
|
|
|
|
|
|
|
|
const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
|
|
|
|
// Extra space for the PID in the filename
|
|
|
|
const int PerfBasicLogger::kFilenameBufferPadding = 16;
|
|
|
|
|
|
|
|
PerfBasicLogger::PerfBasicLogger()
|
|
|
|
: perf_output_handle_(NULL) {
|
|
|
|
// Open the perf JIT dump file.
|
|
|
|
int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
|
|
|
|
ScopedVector<char> perf_dump_name(bufferSize);
|
2014-06-13 16:43:27 +00:00
|
|
|
int size = SNPrintF(
|
2013-11-25 06:44:23 +00:00
|
|
|
perf_dump_name,
|
|
|
|
kFilenameFormatString,
|
2014-06-30 13:25:46 +00:00
|
|
|
base::OS::GetCurrentProcessId());
|
2013-11-25 06:44:23 +00:00
|
|
|
CHECK_NE(size, -1);
|
2014-06-30 13:25:46 +00:00
|
|
|
perf_output_handle_ =
|
|
|
|
base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode);
|
2015-01-30 09:29:25 +00:00
|
|
|
CHECK_NOT_NULL(perf_output_handle_);
|
2013-11-25 06:44:23 +00:00
|
|
|
setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PerfBasicLogger::~PerfBasicLogger() {
|
|
|
|
fclose(perf_output_handle_);
|
|
|
|
perf_output_handle_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PerfBasicLogger::LogRecordedBuffer(Code* code,
|
|
|
|
SharedFunctionInfo*,
|
|
|
|
const char* name,
|
|
|
|
int length) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(code->instruction_start() == code->address() + Code::kHeaderSize);
|
2013-11-25 06:44:23 +00:00
|
|
|
|
2014-06-30 13:25:46 +00:00
|
|
|
base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n",
|
|
|
|
reinterpret_cast<uint64_t>(code->instruction_start()),
|
|
|
|
code->instruction_size(), length, name);
|
2013-11-25 06:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-15 11:35:39 +00:00
|
|
|
// Low-level logging support.
|
2013-07-26 13:50:23 +00:00
|
|
|
#define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
|
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
class LowLevelLogger : public CodeEventLogger {
|
2013-07-15 11:35:39 +00:00
|
|
|
public:
|
|
|
|
explicit LowLevelLogger(const char* file_name);
|
2013-07-19 14:58:53 +00:00
|
|
|
virtual ~LowLevelLogger();
|
2013-07-15 11:35:39 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
virtual void CodeMoveEvent(Address from, Address to);
|
2014-05-22 05:36:27 +00:00
|
|
|
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
2013-07-26 13:50:23 +00:00
|
|
|
virtual void CodeDeleteEvent(Address from);
|
|
|
|
virtual void SnapshotPositionEvent(Address addr, int pos);
|
|
|
|
virtual void CodeMovingGCEvent();
|
2013-07-15 11:35:39 +00:00
|
|
|
|
|
|
|
private:
|
2013-07-19 14:58:53 +00:00
|
|
|
virtual void LogRecordedBuffer(Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
2013-07-26 13:50:23 +00:00
|
|
|
const char* name,
|
|
|
|
int length);
|
2013-07-15 11:35:39 +00:00
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
// Low-level profiling event structures.
|
2013-07-15 11:35:39 +00:00
|
|
|
struct CodeCreateStruct {
|
|
|
|
static const char kTag = 'C';
|
|
|
|
|
|
|
|
int32_t name_size;
|
|
|
|
Address code_address;
|
|
|
|
int32_t code_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct CodeMoveStruct {
|
|
|
|
static const char kTag = 'M';
|
|
|
|
|
|
|
|
Address from_address;
|
|
|
|
Address to_address;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct CodeDeleteStruct {
|
|
|
|
static const char kTag = 'D';
|
|
|
|
|
|
|
|
Address address;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct SnapshotPositionStruct {
|
|
|
|
static const char kTag = 'P';
|
|
|
|
|
|
|
|
Address address;
|
|
|
|
int32_t position;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const char kCodeMovingGCTag = 'G';
|
|
|
|
|
|
|
|
|
|
|
|
// Extension added to V8 log file name to get the low-level log name.
|
|
|
|
static const char kLogExt[];
|
|
|
|
|
|
|
|
// File buffer size of the low-level log. We don't use the default to
|
|
|
|
// minimize the associated overhead.
|
|
|
|
static const int kLogBufferSize = 2 * MB;
|
|
|
|
|
|
|
|
void LogCodeInfo();
|
|
|
|
void LogWriteBytes(const char* bytes, int size);
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void LogWriteStruct(const T& s) {
|
|
|
|
char tag = T::kTag;
|
|
|
|
LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
|
|
|
|
LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE* ll_output_handle_;
|
|
|
|
};
|
|
|
|
|
|
|
|
const char LowLevelLogger::kLogExt[] = ".ll";
|
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
LowLevelLogger::LowLevelLogger(const char* name)
|
|
|
|
: ll_output_handle_(NULL) {
|
|
|
|
// Open the low-level log file.
|
|
|
|
size_t len = strlen(name);
|
|
|
|
ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
|
2014-05-27 07:57:22 +00:00
|
|
|
MemCopy(ll_name.start(), name, len);
|
|
|
|
MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
|
2014-06-30 13:25:46 +00:00
|
|
|
ll_output_handle_ =
|
|
|
|
base::OS::FOpen(ll_name.start(), base::OS::LogFileOpenMode);
|
2013-07-19 15:57:18 +00:00
|
|
|
setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
|
|
|
|
|
|
|
|
LogCodeInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LowLevelLogger::~LowLevelLogger() {
|
|
|
|
fclose(ll_output_handle_);
|
|
|
|
ll_output_handle_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::LogCodeInfo() {
|
|
|
|
#if V8_TARGET_ARCH_IA32
|
|
|
|
const char arch[] = "ia32";
|
2014-06-24 05:27:44 +00:00
|
|
|
#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT
|
2013-07-19 15:57:18 +00:00
|
|
|
const char arch[] = "x64";
|
2014-06-24 05:27:44 +00:00
|
|
|
#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
|
|
|
|
const char arch[] = "x32";
|
2013-07-19 15:57:18 +00:00
|
|
|
#elif V8_TARGET_ARCH_ARM
|
|
|
|
const char arch[] = "arm";
|
2015-01-16 07:42:00 +00:00
|
|
|
#elif V8_TARGET_ARCH_PPC
|
|
|
|
const char arch[] = "ppc";
|
2013-07-19 15:57:18 +00:00
|
|
|
#elif V8_TARGET_ARCH_MIPS
|
|
|
|
const char arch[] = "mips";
|
2014-05-23 16:37:27 +00:00
|
|
|
#elif V8_TARGET_ARCH_X87
|
|
|
|
const char arch[] = "x87";
|
2014-06-24 12:40:20 +00:00
|
|
|
#elif V8_TARGET_ARCH_ARM64
|
|
|
|
const char arch[] = "arm64";
|
2013-07-19 15:57:18 +00:00
|
|
|
#else
|
|
|
|
const char arch[] = "unknown";
|
|
|
|
#endif
|
|
|
|
LogWriteBytes(arch, sizeof(arch));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::LogRecordedBuffer(Code* code,
|
|
|
|
SharedFunctionInfo*,
|
2013-07-26 13:50:23 +00:00
|
|
|
const char* name,
|
|
|
|
int length) {
|
2013-07-19 15:57:18 +00:00
|
|
|
CodeCreateStruct event;
|
2013-07-26 13:50:23 +00:00
|
|
|
event.name_size = length;
|
2013-07-19 15:57:18 +00:00
|
|
|
event.code_address = code->instruction_start();
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(event.code_address == code->address() + Code::kHeaderSize);
|
2013-07-19 15:57:18 +00:00
|
|
|
event.code_size = code->instruction_size();
|
|
|
|
LogWriteStruct(event);
|
2013-07-26 13:50:23 +00:00
|
|
|
LogWriteBytes(name, length);
|
2013-07-19 15:57:18 +00:00
|
|
|
LogWriteBytes(
|
|
|
|
reinterpret_cast<const char*>(code->instruction_start()),
|
|
|
|
code->instruction_size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
|
|
|
|
CodeMoveStruct event;
|
|
|
|
event.from_address = from + Code::kHeaderSize;
|
|
|
|
event.to_address = to + Code::kHeaderSize;
|
|
|
|
LogWriteStruct(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::CodeDeleteEvent(Address from) {
|
|
|
|
CodeDeleteStruct event;
|
|
|
|
event.address = from + Code::kHeaderSize;
|
|
|
|
LogWriteStruct(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
|
|
|
|
SnapshotPositionStruct event;
|
|
|
|
event.address = addr + Code::kHeaderSize;
|
|
|
|
event.position = pos;
|
|
|
|
LogWriteStruct(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
|
|
|
|
size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(static_cast<size_t>(size) == rv);
|
2013-07-19 15:57:18 +00:00
|
|
|
USE(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LowLevelLogger::CodeMovingGCEvent() {
|
|
|
|
const char tag = kCodeMovingGCTag;
|
|
|
|
|
|
|
|
LogWriteBytes(&tag, sizeof(tag));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
#define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
|
2013-07-19 14:58:53 +00:00
|
|
|
|
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
class JitLogger : public CodeEventLogger {
|
|
|
|
public:
|
|
|
|
explicit JitLogger(JitCodeEventHandler code_event_handler);
|
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
virtual void CodeMoveEvent(Address from, Address to);
|
2014-05-22 05:36:27 +00:00
|
|
|
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
|
2013-07-26 13:50:23 +00:00
|
|
|
virtual void CodeDeleteEvent(Address from);
|
|
|
|
virtual void AddCodeLinePosInfoEvent(
|
2013-07-19 15:57:18 +00:00
|
|
|
void* jit_handler_data,
|
|
|
|
int pc_offset,
|
|
|
|
int position,
|
|
|
|
JitCodeEvent::PositionType position_type);
|
2013-07-26 13:50:23 +00:00
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
void* StartCodePosInfoEvent();
|
|
|
|
void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void LogRecordedBuffer(Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
2013-07-26 13:50:23 +00:00
|
|
|
const char* name,
|
|
|
|
int length);
|
2013-07-19 15:57:18 +00:00
|
|
|
|
|
|
|
JitCodeEventHandler code_event_handler_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
|
|
|
|
: code_event_handler_(code_event_handler) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void JitLogger::LogRecordedBuffer(Code* code,
|
|
|
|
SharedFunctionInfo* shared,
|
2013-07-26 13:50:23 +00:00
|
|
|
const char* name,
|
|
|
|
int length) {
|
2013-07-19 15:57:18 +00:00
|
|
|
JitCodeEvent event;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.type = JitCodeEvent::CODE_ADDED;
|
|
|
|
event.code_start = code->instruction_start();
|
|
|
|
event.code_len = code->instruction_size();
|
2014-07-15 08:13:42 +00:00
|
|
|
Handle<SharedFunctionInfo> shared_function_handle;
|
2013-07-19 15:57:18 +00:00
|
|
|
if (shared && shared->script()->IsScript()) {
|
2014-07-15 08:13:42 +00:00
|
|
|
shared_function_handle = Handle<SharedFunctionInfo>(shared);
|
2013-07-19 15:57:18 +00:00
|
|
|
}
|
2014-07-15 08:13:42 +00:00
|
|
|
event.script = ToApiHandle<v8::UnboundScript>(shared_function_handle);
|
2013-07-26 13:50:23 +00:00
|
|
|
event.name.str = name;
|
|
|
|
event.name.len = length;
|
2013-07-19 15:57:18 +00:00
|
|
|
code_event_handler_(&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
void JitLogger::CodeMoveEvent(Address from, Address to) {
|
2013-07-19 15:57:18 +00:00
|
|
|
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 JitLogger::CodeDeleteEvent(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitLogger::AddCodeLinePosInfoEvent(
|
|
|
|
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* JitLogger::StartCodePosInfoEvent() {
|
|
|
|
JitCodeEvent event;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
|
|
|
|
|
|
|
|
code_event_handler_(&event);
|
|
|
|
return event.user_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void JitLogger::EndCodePosInfoEvent(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
//
|
2014-06-30 13:25:46 +00:00
|
|
|
class Profiler: public base::Thread {
|
2008-07-03 15:10:15 +00:00
|
|
|
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;
|
|
|
|
|
2014-10-08 11:33:31 +00:00
|
|
|
if (Succ(head_) == static_cast<int>(base::NoBarrier_Load(&tail_))) {
|
2008-07-03 15:10:15 +00:00
|
|
|
overflow_ = true;
|
|
|
|
} else {
|
|
|
|
buffer_[head_] = *sample;
|
|
|
|
head_ = Succ(head_);
|
2013-09-02 12:26:06 +00:00
|
|
|
buffer_semaphore_.Signal(); // Tell we have an element.
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-26 14:52:26 +00:00
|
|
|
virtual void Run();
|
|
|
|
|
|
|
|
// Pause and Resume TickSample data collection.
|
|
|
|
void pause() { paused_ = true; }
|
|
|
|
void resume() { paused_ = false; }
|
|
|
|
|
|
|
|
private:
|
2008-07-03 15:10:15 +00:00
|
|
|
// Waits for a signal and removes profiling data.
|
|
|
|
bool Remove(TickSample* sample) {
|
2013-09-02 12:26:06 +00:00
|
|
|
buffer_semaphore_.Wait(); // Wait for an element.
|
2014-10-08 11:33:31 +00:00
|
|
|
*sample = buffer_[base::NoBarrier_Load(&tail_)];
|
2008-07-03 15:10:15 +00:00
|
|
|
bool result = overflow_;
|
2014-10-08 11:33:31 +00:00
|
|
|
base::NoBarrier_Store(&tail_, static_cast<base::Atomic32>(
|
|
|
|
Succ(base::NoBarrier_Load(&tail_))));
|
2008-07-03 15:10:15 +00:00
|
|
|
overflow_ = false;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2014-10-08 11:33:31 +00:00
|
|
|
base::Atomic32 tail_; // Index to the buffer tail.
|
2008-07-03 15:10:15 +00:00
|
|
|
bool overflow_; // Tell whether a buffer overflow has occurred.
|
2013-08-26 14:52:26 +00:00
|
|
|
// Sempahore used for buffer synchronization.
|
2014-06-30 13:25:46 +00:00
|
|
|
base::Semaphore buffer_semaphore_;
|
2008-07-03 15:10:15 +00:00
|
|
|
|
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.
|
2014-10-09 07:51:35 +00:00
|
|
|
base::Atomic32 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) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(profiler_ == NULL);
|
2008-07-03 15:10:15 +00:00
|
|
|
profiler_ = profiler;
|
2010-12-07 11:31:57 +00:00
|
|
|
IncreaseProfilingDepth();
|
2013-08-29 10:42:55 +00:00
|
|
|
if (!IsActive()) Start();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClearProfiler() {
|
|
|
|
profiler_ = NULL;
|
2012-12-07 13:47:42 +00:00
|
|
|
if (IsActive()) Stop();
|
2013-08-29 14:03:38 +00:00
|
|
|
DecreaseProfilingDepth();
|
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)
|
2014-08-12 13:33:35 +00:00
|
|
|
: base::Thread(Options("v8:Profiler")),
|
2011-06-10 09:54:04 +00:00
|
|
|
isolate_(isolate),
|
2011-01-04 09:09:50 +00:00
|
|
|
head_(0),
|
2009-10-28 09:13:11 +00:00
|
|
|
overflow_(false),
|
2013-09-02 12:26:06 +00:00
|
|
|
buffer_semaphore_(0),
|
2009-10-28 09:13:11 +00:00
|
|
|
engaged_(false),
|
2014-10-08 11:33:31 +00:00
|
|
|
paused_(false) {
|
|
|
|
base::NoBarrier_Store(&tail_, 0);
|
2014-10-09 07:51:35 +00:00
|
|
|
base::NoBarrier_Store(&running_, 0);
|
2014-10-08 11:33:31 +00:00
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
void Profiler::Engage() {
|
2009-10-28 09:13:11 +00:00
|
|
|
if (engaged_) return;
|
|
|
|
engaged_ = true;
|
|
|
|
|
2014-06-30 13:25:46 +00:00
|
|
|
std::vector<base::OS::SharedLibraryAddress> addresses =
|
|
|
|
base::OS::GetSharedLibraryAddresses();
|
2014-06-12 17:06:24 +00:00
|
|
|
for (size_t i = 0; i < addresses.size(); ++i) {
|
|
|
|
LOG(isolate_, SharedLibraryEvent(
|
|
|
|
addresses[i].library_path, addresses[i].start, addresses[i].end));
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Start thread processing the profiler buffer.
|
2014-10-09 07:51:35 +00:00
|
|
|
base::NoBarrier_Store(&running_, 1);
|
2008-07-03 15:10:15 +00:00
|
|
|
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-07-19 15:57:18 +00:00
|
|
|
isolate_->logger()->ticker_->ClearProfiler();
|
2012-08-28 14:43:28 +00:00
|
|
|
|
2013-07-19 15:57:18 +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.
|
2014-10-09 07:51:35 +00:00
|
|
|
base::NoBarrier_Store(&running_, 0);
|
2013-07-19 15:57:18 +00:00
|
|
|
TickSample sample;
|
|
|
|
// Reset 'paused_' flag, otherwise semaphore may not be signalled.
|
|
|
|
resume();
|
|
|
|
Insert(&sample);
|
|
|
|
Join();
|
2012-08-28 14:43:28 +00:00
|
|
|
|
2013-09-11 07:28:47 +00:00
|
|
|
LOG(isolate_, UncheckedStringEvent("profiler", "end"));
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
void Profiler::Run() {
|
|
|
|
TickSample sample;
|
|
|
|
bool overflow = Remove(&sample);
|
2014-10-09 07:51:35 +00:00
|
|
|
while (base::NoBarrier_Load(&running_)) {
|
2013-07-19 15:57:18 +00:00
|
|
|
LOG(isolate_, TickEvent(&sample, overflow));
|
|
|
|
overflow = Remove(&sample);
|
|
|
|
}
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
//
|
|
|
|
// Logger class implementation.
|
|
|
|
//
|
2013-02-18 18:06:12 +00:00
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
Logger::Logger(Isolate* isolate)
|
|
|
|
: isolate_(isolate),
|
|
|
|
ticker_(NULL),
|
|
|
|
profiler_(NULL),
|
|
|
|
log_events_(NULL),
|
2013-08-29 10:42:55 +00:00
|
|
|
is_logging_(false),
|
2013-07-19 15:57:18 +00:00
|
|
|
log_(new Log(this)),
|
2013-11-25 06:44:23 +00:00
|
|
|
perf_basic_logger_(NULL),
|
|
|
|
perf_jit_logger_(NULL),
|
2013-07-19 15:57:18 +00:00
|
|
|
ll_logger_(NULL),
|
|
|
|
jit_logger_(NULL),
|
2013-07-26 13:50:23 +00:00
|
|
|
listeners_(5),
|
2013-08-29 09:15:13 +00:00
|
|
|
is_initialized_(false) {
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
2013-07-19 15:57:18 +00:00
|
|
|
Logger::~Logger() {
|
|
|
|
delete log_;
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
|
2009-05-05 15:57:47 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void Logger::addCodeEventListener(CodeEventListener* listener) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(!hasCodeEventListener(listener));
|
2013-07-26 13:50:23 +00:00
|
|
|
listeners_.Add(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::removeCodeEventListener(CodeEventListener* listener) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(hasCodeEventListener(listener));
|
2013-07-26 13:50:23 +00:00
|
|
|
listeners_.RemoveElement(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Logger::hasCodeEventListener(CodeEventListener* listener) {
|
|
|
|
return listeners_.Contains(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-29 06:56:23 +00:00
|
|
|
void Logger::ProfilerBeginEvent() {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("profiler,\"begin\",%d", 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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("%s,\"%s\"", name, value);
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("%s,%d", name, value);
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("%s,%" V8_PTR_PREFIX "d", name, value);
|
2010-09-30 07:22:53 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("%s,0x%" V8PRIxPTR, 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, ...) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(log_->IsEnabled() && FLAG_log_api);
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
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);
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,check-security,\"%s\"", str.get());
|
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()) {
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,check-security,symbol(hash %x)", Symbol::cast(key)->Hash());
|
2013-03-22 16:51:28 +00:00
|
|
|
} else {
|
|
|
|
SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
|
|
|
|
DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,check-security,symbol(\"%s\" hash %x)", str.get(),
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol::cast(key)->Hash());
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
} else if (key->IsUndefined()) {
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,check-security,undefined");
|
2008-07-03 15:10:15 +00:00
|
|
|
} else {
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,check-security,['no-name']");
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-12 17:06:24 +00:00
|
|
|
void Logger::SharedLibraryEvent(const std::string& library_path,
|
2009-06-16 12:52:02 +00:00
|
|
|
uintptr_t start,
|
|
|
|
uintptr_t end) {
|
2015-01-20 16:06:03 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR,
|
|
|
|
library_path.c_str(), 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-07-03 10:10:27 +00:00
|
|
|
void Logger::CodeDeoptEvent(Code* code) {
|
|
|
|
if (!log_->IsEnabled()) return;
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(FLAG_log_internal_timer_events);
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-08-29 09:15:13 +00:00
|
|
|
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("code-deopt,%ld,%d", since_epoch, code->CodeSize());
|
2013-07-03 10:10:27 +00:00
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-13 09:07:56 +00:00
|
|
|
void Logger::CurrentTimeEvent() {
|
|
|
|
if (!log_->IsEnabled()) return;
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(FLAG_log_internal_timer_events);
|
2014-06-13 09:07:56 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
|
|
|
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("current-time,%ld", since_epoch);
|
2014-06-13 09:07:56 +00:00
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-16 08:14:50 +00:00
|
|
|
void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
|
2012-11-26 08:56:59 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(FLAG_log_internal_timer_events);
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-08-29 09:15:13 +00:00
|
|
|
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
|
2014-07-14 10:47:40 +00:00
|
|
|
const char* format = (se == START) ? "timer-event-start,\"%s\",%ld"
|
|
|
|
: "timer-event-end,\"%s\",%ld";
|
2013-01-28 13:55:40 +00:00
|
|
|
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) {
|
2014-07-16 08:14:50 +00:00
|
|
|
LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(isolate->current_vm_state() == JS);
|
2013-04-24 14:44:08 +00:00
|
|
|
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) {
|
2014-07-16 08:14:50 +00:00
|
|
|
LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(isolate->current_vm_state() == EXTERNAL);
|
2013-04-24 14:44:08 +00:00
|
|
|
isolate->set_current_vm_state(JS);
|
2012-11-28 15:11:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-16 08:14:50 +00:00
|
|
|
template <class TimerEvent>
|
|
|
|
void TimerEventScope<TimerEvent>::LogTimerEvent(Logger::StartEnd se) {
|
2014-10-14 14:45:03 +00:00
|
|
|
Logger::CallEventLogger(isolate_, TimerEvent::name(), se,
|
|
|
|
TimerEvent::expose_to_api());
|
2012-11-26 08:56:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-16 08:14:50 +00:00
|
|
|
// Instantiate template methods.
|
|
|
|
#define V(TimerName, expose) \
|
|
|
|
template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
|
|
|
|
Logger::StartEnd se);
|
|
|
|
TIMER_EVENTS_LIST(V)
|
|
|
|
#undef V
|
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":"")
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2008-09-11 11:24:45 +00:00
|
|
|
|
2014-04-16 13:28:11 +00:00
|
|
|
Handle<Object> source = Object::GetProperty(
|
|
|
|
isolate_, regexp, "source").ToHandleChecked();
|
2008-09-11 11:24:45 +00:00
|
|
|
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
|
2014-04-16 13:28:11 +00:00
|
|
|
Handle<Object> global = Object::GetProperty(
|
|
|
|
isolate_, regexp, "global").ToHandleChecked();
|
2008-09-11 11:24:45 +00:00
|
|
|
if (global->IsTrue()) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('g');
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
// ignorecase flag
|
2014-04-16 13:28:11 +00:00
|
|
|
Handle<Object> ignorecase = Object::GetProperty(
|
|
|
|
isolate_, regexp, "ignoreCase").ToHandleChecked();
|
2008-09-11 11:24:45 +00:00
|
|
|
if (ignorecase->IsTrue()) {
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append('i');
|
2008-09-11 11:24:45 +00:00
|
|
|
}
|
|
|
|
// multiline flag
|
2014-04-16 13:28:11 +00:00
|
|
|
Handle<Object> multiline = Object::GetProperty(
|
|
|
|
isolate_, regexp, "multiline").ToHandleChecked();
|
2008-09-11 11:24:45 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2009-02-17 12:49:35 +00:00
|
|
|
msg.Append("regexp-compile,");
|
2008-09-11 11:24:45 +00:00
|
|
|
LogRegExpSource(regexp);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append(in_cache ? ",hit" : ",miss");
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,check-security,%u", index);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Logger::ApiNamedPropertyAccess(const char* tag,
|
|
|
|
JSObject* holder,
|
|
|
|
Object* name) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(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);
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,%s,\"%s\",\"%s\"", tag, class_name.get(),
|
2013-12-09 07:41:20 +00:00
|
|
|
property_name.get());
|
2013-03-04 15:00:57 +00:00
|
|
|
} else {
|
2013-03-22 16:51:28 +00:00
|
|
|
Symbol* symbol = Symbol::cast(name);
|
|
|
|
uint32_t hash = symbol->Hash();
|
|
|
|
if (symbol->name()->IsUndefined()) {
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,%s,\"%s\",symbol(hash %x)", tag, class_name.get(), hash);
|
2013-03-22 16:51:28 +00:00
|
|
|
} else {
|
|
|
|
SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
|
|
|
|
DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)", tag, class_name.get(),
|
|
|
|
str.get(), hash);
|
2013-03-22 16:51:28 +00:00
|
|
|
}
|
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);
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,%s,\"%s\",%u", tag, class_name.get(), index);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
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);
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,%s,\"%s\"", tag, class_name.get());
|
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;
|
2014-07-14 10:47:40 +00:00
|
|
|
ApiEvent("api,%s", 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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("new,%s,0x%" V8PRIxPTR ",%u", 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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("delete,%s,0x%" V8PRIxPTR, 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-07-18 17:19:31 +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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
msg.Append("%s,%s,-2,",
|
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);
|
2013-12-09 07:41:20 +00:00
|
|
|
msg.Append(",1,\"%s%s\"", prefix, str.get());
|
2013-03-04 15:00:57 +00:00
|
|
|
} 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);
|
2013-12-09 07:41:20 +00:00
|
|
|
msg.Append(",1,symbol(\"%s\" hash %x)", prefix, str.get(),
|
|
|
|
symbol->Hash());
|
2013-03-22 16:51:28 +00:00
|
|
|
}
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2009-11-23 09:19:24 +00:00
|
|
|
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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CallbackEvent(name, entry_point));
|
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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(GetterCallbackEvent(name, entry_point));
|
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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(SetterCallbackEvent(name, entry_point));
|
2013-03-04 15:00:57 +00:00
|
|
|
CallbackEventInternal("set ", name, entry_point);
|
2009-11-23 09:19:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-18 17:19:31 +00:00
|
|
|
static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
|
|
|
|
Logger::LogEventsAndTags tag,
|
|
|
|
Code* code) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(msg);
|
2013-06-24 12:55:19 +00:00
|
|
|
msg->Append("%s,%s,%d,",
|
2013-07-18 17:19:31 +00:00
|
|
|
kLogEventsNames[Logger::CODE_CREATION_EVENT],
|
2013-06-24 12:55:19 +00:00
|
|
|
kLogEventsNames[tag],
|
|
|
|
code->kind());
|
|
|
|
msg->AppendAddress(code->address());
|
|
|
|
msg->Append(",%d,", code->ExecutableSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-24 08:40:38 +00:00
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
const char* comment) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeCreateEvent(tag, code, comment));
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
|
2013-06-24 08:40:38 +00:00
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
AppendCodeCreateHeader(&msg, tag, code);
|
|
|
|
msg.AppendDoubleQuotedString(comment);
|
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
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
|
|
|
Code* code,
|
2013-03-04 15:00:57 +00:00
|
|
|
Name* name) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeCreateEvent(tag, code, name));
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeCreateEvent(tag, code, name));
|
2013-06-24 08:40:38 +00:00
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
AppendCodeCreateHeader(&msg, tag, code);
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
msg.Append('"');
|
|
|
|
msg.AppendDetailed(String::cast(name), false);
|
|
|
|
msg.Append('"');
|
|
|
|
} else {
|
2013-07-18 17:19:31 +00:00
|
|
|
msg.AppendSymbolName(Symbol::cast(name));
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2011-04-29 16:06:25 +00:00
|
|
|
msg.WriteToLogFile();
|
2011-02-22 16:31:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
|
2013-06-24 08:40:38 +00:00
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2014-09-17 15:29:42 +00:00
|
|
|
if (code == isolate_->builtins()->builtin(Builtins::kCompileLazy)) return;
|
2011-03-18 20:35:07 +00:00
|
|
|
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
AppendCodeCreateHeader(&msg, tag, code);
|
2013-03-04 15:00:57 +00:00
|
|
|
if (name->IsString()) {
|
|
|
|
SmartArrayPointer<char> str =
|
|
|
|
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2013-12-09 07:41:20 +00:00
|
|
|
msg.Append("\"%s\"", str.get());
|
2013-03-04 15:00:57 +00:00
|
|
|
} else {
|
2013-07-18 17:19:31 +00:00
|
|
|
msg.AppendSymbolName(Symbol::cast(name));
|
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-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-08-23 17:20:54 +00:00
|
|
|
Name* source, int line, int column) {
|
2013-10-10 13:15:47 +00:00
|
|
|
PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
2013-10-10 13:15:47 +00:00
|
|
|
CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
|
|
|
|
column));
|
2013-06-24 08:40:38 +00:00
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
AppendCodeCreateHeader(&msg, tag, code);
|
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);
|
2013-12-09 07:41:20 +00:00
|
|
|
msg.Append("\"%s ", name.get());
|
2013-03-04 15:00:57 +00:00
|
|
|
if (source->IsString()) {
|
|
|
|
SmartArrayPointer<char> sourcestr =
|
|
|
|
String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
2013-12-09 07:41:20 +00:00
|
|
|
msg.Append("%s", sourcestr.get());
|
2013-03-04 15:00:57 +00:00
|
|
|
} else {
|
2013-07-18 17:19:31 +00:00
|
|
|
msg.AppendSymbolName(Symbol::cast(source));
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2013-08-23 17:20:54 +00:00
|
|
|
msg.Append(":%d:%d\",", line, column);
|
2011-02-22 16:31:24 +00:00
|
|
|
msg.AppendAddress(shared->address());
|
|
|
|
msg.Append(",%s", ComputeMarker(code));
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2009-02-03 10:52:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
|
|
|
Code* code,
|
|
|
|
int args_count) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
|
2013-06-24 08:40:38 +00:00
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
AppendCodeCreateHeader(&msg, tag, code);
|
|
|
|
msg.Append("\"args_count: %d\"", args_count);
|
2009-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-22 05:36:27 +00:00
|
|
|
void Logger::CodeDisableOptEvent(Code* code,
|
|
|
|
SharedFunctionInfo* shared) {
|
|
|
|
PROFILER_LOG(CodeDisableOptEvent(code, shared));
|
|
|
|
|
|
|
|
if (!is_logging_code_events()) return;
|
|
|
|
CALL_LISTENERS(CodeDisableOptEvent(code, shared));
|
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
|
|
|
Log::MessageBuilder msg(log_);
|
|
|
|
msg.Append("%s,", kLogEventsNames[CODE_DISABLE_OPT_EVENT]);
|
|
|
|
SmartArrayPointer<char> name =
|
|
|
|
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
|
|
|
msg.Append("\"%s\",", name.get());
|
2014-11-13 09:55:48 +00:00
|
|
|
msg.Append("\"%s\"", GetBailoutReason(shared->disable_optimization_reason()));
|
2014-05-22 05:36:27 +00:00
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-19 16:45:11 +00:00
|
|
|
void Logger::CodeMovingGCEvent() {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeMovingGCEvent());
|
|
|
|
|
|
|
|
if (!is_logging_code_events()) return;
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_ll_prof) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeMovingGCEvent());
|
2014-06-30 13:25:46 +00:00
|
|
|
base::OS::SignalCodeMovingGC();
|
2010-10-19 16:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-31 09:06:37 +00:00
|
|
|
void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(RegExpCodeCreateEvent(code, source));
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
|
2013-06-24 08:40:38 +00:00
|
|
|
|
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2013-06-24 12:55:19 +00:00
|
|
|
AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
|
|
|
|
msg.Append('"');
|
2009-03-31 09:06:37 +00:00
|
|
|
msg.AppendDetailed(source, false);
|
2013-06-24 12:55:19 +00:00
|
|
|
msg.Append('"');
|
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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeMoveEvent(from, to));
|
|
|
|
|
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeMoveEvent(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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(CodeDeleteEvent(from));
|
|
|
|
|
|
|
|
if (!is_logging_code_events()) return;
|
2013-07-26 13:50:23 +00:00
|
|
|
CALL_LISTENERS(CodeDeleteEvent(from));
|
2013-07-19 15:57:18 +00:00
|
|
|
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-19 15:57:18 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
|
|
|
msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
|
|
|
|
msg.AppendAddress(from);
|
|
|
|
msg.WriteToLogFile();
|
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
|
|
|
}
|
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
|
|
|
|
int pc_offset,
|
|
|
|
int position) {
|
2013-07-18 13:18:46 +00:00
|
|
|
JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
|
|
|
|
pc_offset,
|
|
|
|
position,
|
|
|
|
JitCodeEvent::POSITION));
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
|
|
|
|
int pc_offset,
|
|
|
|
int position) {
|
2013-07-18 13:18:46 +00:00
|
|
|
JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
|
|
|
|
pc_offset,
|
|
|
|
position,
|
|
|
|
JitCodeEvent::STATEMENT_POSITION));
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
|
2013-07-18 13:18:46 +00:00
|
|
|
if (jit_logger_ != NULL) {
|
|
|
|
pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 14:58:53 +00:00
|
|
|
|
2013-02-18 18:06:12 +00:00
|
|
|
void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
|
|
|
|
void* jit_handler_data) {
|
2013-07-18 13:18:46 +00:00
|
|
|
JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
|
2013-02-18 18:06:12 +00:00
|
|
|
}
|
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
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
2013-07-26 13:50:23 +00:00
|
|
|
void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
|
|
|
|
if (code_name == NULL) return; // Not a code object.
|
|
|
|
Log::MessageBuilder msg(log_);
|
|
|
|
msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
|
|
|
|
msg.AppendDoubleQuotedString(code_name);
|
|
|
|
msg.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
2013-07-15 11:35:39 +00:00
|
|
|
LL_LOG(SnapshotPositionEvent(addr, pos));
|
2011-04-29 16:06:25 +00:00
|
|
|
if (!FLAG_log_snapshot_positions) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
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.WriteToLogFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-10 12:00:27 +00:00
|
|
|
void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
|
2013-07-23 08:12:15 +00:00
|
|
|
PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
|
|
|
|
|
|
|
|
if (!is_logging_code_events()) return;
|
2011-03-10 12:00:27 +00:00
|
|
|
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) {
|
2013-07-23 08:12:15 +00:00
|
|
|
if (!FLAG_log_code || !log_->IsEnabled()) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
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-02-17 08:21:24 +00:00
|
|
|
msg.WriteToLogFile();
|
2008-12-19 13:12:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
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;
|
2014-06-30 13:25:46 +00:00
|
|
|
if (base::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
|
|
|
}
|
2014-06-30 13:25:46 +00:00
|
|
|
msg.Append("%.0f", base::OS::TimeCurrentMillis());
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
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-07-18 17:19:31 +00:00
|
|
|
msg.AppendSymbolName(Symbol::cast(name));
|
2013-03-04 15:00:57 +00:00
|
|
|
}
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
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).
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f", space, kind,
|
|
|
|
base::OS::TimeCurrentMillis());
|
2009-07-20 09:38:44 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("heap-sample-end,\"%s\",\"%s\"", space, kind);
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("heap-sample-item,%s,%d,%d", type, number, bytes);
|
2009-02-17 12:49:35 +00:00
|
|
|
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;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("debug-tag,%s", call_site_tag);
|
2009-02-17 12:49:35 +00:00
|
|
|
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();
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2014-07-14 10:47:40 +00:00
|
|
|
msg.Append("debug-queue-event,%s,%15.3f,%s", event_type,
|
|
|
|
base::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) {
|
2015-01-20 16:06:03 +00:00
|
|
|
if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
|
2013-07-18 17:19:31 +00:00
|
|
|
Log::MessageBuilder msg(log_);
|
2010-12-07 13:24:22 +00:00
|
|
|
msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
|
|
|
|
msg.AppendAddress(sample->pc);
|
2013-08-29 09:15:13 +00:00
|
|
|
msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
|
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");
|
|
|
|
}
|
2014-06-24 16:00:51 +00:00
|
|
|
for (unsigned 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.WriteToLogFile();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2009-01-29 19:47:00 +00:00
|
|
|
|
|
|
|
|
2013-08-29 10:42:55 +00:00
|
|
|
void Logger::StopProfiler() {
|
2011-03-18 20:35:07 +00:00
|
|
|
if (!log_->IsEnabled()) return;
|
2011-07-01 09:35:16 +00:00
|
|
|
if (profiler_ != NULL) {
|
2013-08-29 10:42:55 +00:00
|
|
|
profiler_->pause();
|
|
|
|
is_logging_ = false;
|
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() {
|
2013-08-29 10:42:55 +00:00
|
|
|
StopProfiler();
|
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) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
|
2010-12-07 11:31:57 +00:00
|
|
|
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.
|
2013-12-02 13:14:07 +00:00
|
|
|
case Code::BINARY_OP_IC:
|
2013-06-03 09:46:32 +00:00
|
|
|
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;
|
2013-06-24 12:55:19 +00:00
|
|
|
case Code::REGEXP:
|
|
|
|
description = "Regular expression code";
|
|
|
|
tag = Logger::REG_EXP_TAG;
|
|
|
|
break;
|
2013-06-03 09:46:32 +00:00
|
|
|
case Code::BUILTIN:
|
|
|
|
description = "A builtin from the snapshot";
|
|
|
|
tag = Logger::BUILTIN_TAG;
|
|
|
|
break;
|
2013-09-30 13:53:21 +00:00
|
|
|
case Code::HANDLER:
|
|
|
|
description = "An IC handler from the snapshot";
|
|
|
|
tag = Logger::HANDLER_TAG;
|
|
|
|
break;
|
2013-06-03 09:46:32 +00:00
|
|
|
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;
|
2014-04-30 14:33:35 +00:00
|
|
|
case Code::CALL_IC:
|
|
|
|
description = "A call IC from the snapshot";
|
|
|
|
tag = Logger::CALL_IC_TAG;
|
|
|
|
break;
|
2013-06-03 09:46:32 +00:00
|
|
|
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;
|
2013-06-25 09:34:22 +00:00
|
|
|
case Code::NUMBER_OF_KINDS:
|
|
|
|
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-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()));
|
2014-04-16 13:28:11 +00:00
|
|
|
int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
|
2013-08-23 17:20:54 +00:00
|
|
|
int column_num =
|
2014-04-16 13:28:11 +00:00
|
|
|
Script::GetColumnNumber(script, shared->start_position()) + 1;
|
2011-09-14 11:47:03 +00:00
|
|
|
if (script->name()->IsString()) {
|
2013-06-13 11:09:19 +00:00
|
|
|
Handle<String> script_name(String::cast(script->name()));
|
|
|
|
if (line_num > 0) {
|
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,
|
2013-08-23 17:20:54 +00:00
|
|
|
*script_name, line_num, column_num));
|
2011-09-14 11:47:03 +00:00
|
|
|
} 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-07-07 11:42:30 +00:00
|
|
|
*code, *shared, NULL,
|
2013-08-23 17:20:54 +00:00
|
|
|
isolate_->heap()->empty_string(), line_num, column_num));
|
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) {
|
2014-09-17 15:29:42 +00:00
|
|
|
if (code_objects[i].is_identical_to(isolate_->builtins()->CompileLazy()))
|
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
|
|
|
|
2014-09-30 10:29:32 +00:00
|
|
|
static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT
|
2014-07-03 07:18:30 +00:00
|
|
|
Isolate* isolate) {
|
|
|
|
if (FLAG_logfile_per_isolate) os << "isolate-" << isolate << "-";
|
2013-07-15 11:35:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-30 10:29:32 +00:00
|
|
|
static void PrepareLogFileName(std::ostream& os, // NOLINT
|
2014-07-03 07:18:30 +00:00
|
|
|
Isolate* isolate, const char* file_name) {
|
|
|
|
AddIsolateIdIfNeeded(os, isolate);
|
2014-05-09 08:40:18 +00:00
|
|
|
for (const char* p = file_name; *p; p++) {
|
|
|
|
if (*p == '%') {
|
|
|
|
p++;
|
|
|
|
switch (*p) {
|
|
|
|
case '\0':
|
|
|
|
// If there's a % at the end of the string we back up
|
|
|
|
// one character so we can escape the loop properly.
|
|
|
|
p--;
|
|
|
|
break;
|
|
|
|
case 'p':
|
2014-07-03 07:18:30 +00:00
|
|
|
os << base::OS::GetCurrentProcessId();
|
2014-05-09 08:40:18 +00:00
|
|
|
break;
|
2014-07-03 07:18:30 +00:00
|
|
|
case 't':
|
2014-05-09 08:40:18 +00:00
|
|
|
// %t expands to the current time in milliseconds.
|
2014-07-03 07:18:30 +00:00
|
|
|
os << static_cast<int64_t>(base::OS::TimeCurrentMillis());
|
2014-05-09 08:40:18 +00:00
|
|
|
break;
|
|
|
|
case '%':
|
|
|
|
// %% expands (contracts really) to %.
|
2014-07-03 07:18:30 +00:00
|
|
|
os << '%';
|
2014-05-09 08:40:18 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// All other %'s expand to themselves.
|
2014-07-03 07:18:30 +00:00
|
|
|
os << '%' << *p;
|
2014-05-09 08:40:18 +00:00
|
|
|
break;
|
2013-07-15 11:35:39 +00:00
|
|
|
}
|
2014-05-09 08:40:18 +00:00
|
|
|
} else {
|
2014-07-03 07:18:30 +00:00
|
|
|
os << *p;
|
2013-07-15 11:35:39 +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;
|
|
|
|
}
|
|
|
|
|
2014-09-30 10:29:32 +00:00
|
|
|
std::ostringstream log_file_name;
|
2014-07-03 07:18:30 +00:00
|
|
|
PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
|
2014-09-30 10:29:32 +00:00
|
|
|
log_->Initialize(log_file_name.str().c_str());
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2013-11-25 06:44:23 +00:00
|
|
|
|
|
|
|
if (FLAG_perf_basic_prof) {
|
|
|
|
perf_basic_logger_ = new PerfBasicLogger();
|
|
|
|
addCodeEventListener(perf_basic_logger_);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FLAG_perf_jit_prof) {
|
|
|
|
perf_jit_logger_ = new PerfJitLogger();
|
|
|
|
addCodeEventListener(perf_jit_logger_);
|
|
|
|
}
|
|
|
|
|
2013-07-15 11:35:39 +00:00
|
|
|
if (FLAG_ll_prof) {
|
2014-09-30 10:29:32 +00:00
|
|
|
ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
|
2013-07-26 13:50:23 +00:00
|
|
|
addCodeEventListener(ll_logger_);
|
2013-07-15 11:35:39 +00:00
|
|
|
}
|
2010-10-19 16:45:11 +00:00
|
|
|
|
2011-06-10 09:54:04 +00:00
|
|
|
ticker_ = new Ticker(isolate, kSamplingIntervalMs);
|
|
|
|
|
2013-04-24 14:44:08 +00:00
|
|
|
if (Log::InitLogAtStart()) {
|
2013-08-29 10:42:55 +00:00
|
|
|
is_logging_ = true;
|
2010-03-01 10:41:34 +00:00
|
|
|
}
|
2009-06-24 13:09:34 +00:00
|
|
|
|
2015-01-20 16:06:03 +00:00
|
|
|
if (FLAG_log_internal_timer_events || FLAG_prof_cpp) timer_.Start();
|
2014-10-08 14:08:12 +00:00
|
|
|
|
2015-01-20 16:06:03 +00:00
|
|
|
if (FLAG_prof_cpp) {
|
2011-06-10 09:42:08 +00:00
|
|
|
profiler_ = new Profiler(isolate);
|
2013-08-29 10:42:55 +00:00
|
|
|
is_logging_ = true;
|
|
|
|
profiler_->Engage();
|
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) {
|
2013-07-18 13:18:46 +00:00
|
|
|
if (jit_logger_) {
|
2013-07-26 13:50:23 +00:00
|
|
|
removeCodeEventListener(jit_logger_);
|
2013-07-18 13:18:46 +00:00
|
|
|
delete jit_logger_;
|
|
|
|
jit_logger_ = NULL;
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
|
2013-07-18 13:18:46 +00:00
|
|
|
if (event_handler) {
|
|
|
|
jit_logger_ = new JitLogger(event_handler);
|
2013-07-26 13:50:23 +00:00
|
|
|
addCodeEventListener(jit_logger_);
|
|
|
|
if (options & kJitCodeEventEnumExisting) {
|
|
|
|
HandleScope scope(isolate_);
|
|
|
|
LogCodeObjects();
|
|
|
|
LogCompiledFunctions();
|
|
|
|
}
|
2012-08-28 14:43:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2013-11-25 06:44:23 +00:00
|
|
|
if (perf_basic_logger_) {
|
|
|
|
removeCodeEventListener(perf_basic_logger_);
|
|
|
|
delete perf_basic_logger_;
|
|
|
|
perf_basic_logger_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (perf_jit_logger_) {
|
|
|
|
removeCodeEventListener(perf_jit_logger_);
|
|
|
|
delete perf_jit_logger_;
|
|
|
|
perf_jit_logger_ = NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-15 11:35:39 +00:00
|
|
|
if (ll_logger_) {
|
2013-07-26 13:50:23 +00:00
|
|
|
removeCodeEventListener(ll_logger_);
|
2013-07-15 11:35:39 +00:00
|
|
|
delete ll_logger_;
|
|
|
|
ll_logger_ = NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-18 13:18:46 +00:00
|
|
|
if (jit_logger_) {
|
2013-07-26 13:50:23 +00:00
|
|
|
removeCodeEventListener(jit_logger_);
|
2013-07-18 13:18:46 +00:00
|
|
|
delete jit_logger_;
|
|
|
|
jit_logger_ = NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-13 11:31:22 +00:00
|
|
|
return log_->Close();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|