Fix CPU profiling for Crankshaft.

The main issue was due to multiple recompilations of functions.  Now
code objects are grouped by function using SFI object address.
JSFunction objects are no longer tracked, instead we track SFI object
moves. To pick a correct code version, we now sample return addresses
instead of JSFunction addresses.

tools/{linux|mac|windows}-tickprocessor scripts differentiate
between code optimization states for the same function
(using * and ~ prefixes introduced earlier).

DevTools CPU profiler treats all variants of function code as
a single function.

ll_prof treats each optimized variant as a separate entry, because
it can disassemble each one of them.

tickprocessor.py not updated -- it is deprecated and will be removed.

BUG=v8/1087,b/3178160
TEST=all existing tests pass, including Chromium layout tests

Review URL: http://codereview.chromium.org/6551011

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 08377c84
...@@ -261,10 +261,8 @@ static bool MakeCrankshaftCode(CompilationInfo* info) { ...@@ -261,10 +261,8 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
Handle<SharedFunctionInfo> shared = info->shared_info(); Handle<SharedFunctionInfo> shared = info->shared_info();
shared->EnableDeoptimizationSupport(*unoptimized.code()); shared->EnableDeoptimizationSupport(*unoptimized.code());
// The existing unoptimized code was replaced with the new one. // The existing unoptimized code was replaced with the new one.
Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, Compiler::RecordFunctionCompilation(
Handle<String>(shared->DebugName()), Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
shared->start_position(),
&unoptimized);
} }
} }
...@@ -414,13 +412,25 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { ...@@ -414,13 +412,25 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
return Handle<SharedFunctionInfo>::null(); return Handle<SharedFunctionInfo>::null();
} }
// Allocate function.
ASSERT(!info->code().is_null()); ASSERT(!info->code().is_null());
Handle<SharedFunctionInfo> result =
Factory::NewSharedFunctionInfo(
lit->name(),
lit->materialized_literal_count(),
info->code(),
SerializedScopeInfo::Create(info->scope()));
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Compiler::SetFunctionInfo(result, lit, true, script);
if (script->name()->IsString()) { if (script->name()->IsString()) {
PROFILE(CodeCreateEvent( PROFILE(CodeCreateEvent(
info->is_eval() info->is_eval()
? Logger::EVAL_TAG ? Logger::EVAL_TAG
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*info->code(), *info->code(),
*result,
String::cast(script->name()))); String::cast(script->name())));
GDBJIT(AddCode(Handle<String>(String::cast(script->name())), GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
script, script,
...@@ -431,21 +441,11 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { ...@@ -431,21 +441,11 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
? Logger::EVAL_TAG ? Logger::EVAL_TAG
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*info->code(), *info->code(),
"")); *result,
Heap::empty_string()));
GDBJIT(AddCode(Handle<String>(), script, info->code())); GDBJIT(AddCode(Handle<String>(), script, info->code()));
} }
// Allocate function.
Handle<SharedFunctionInfo> result =
Factory::NewSharedFunctionInfo(
lit->name(),
lit->materialized_literal_count(),
info->code(),
SerializedScopeInfo::Create(info->scope()));
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Compiler::SetFunctionInfo(result, lit, true, script);
// Hint to the runtime system used when allocating space for initial // Hint to the runtime system used when allocating space for initial
// property space by setting the expected number of properties for // property space by setting the expected number of properties for
// the instances of the function. // the instances of the function.
...@@ -612,10 +612,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) { ...@@ -612,10 +612,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
ASSERT(!info->code().is_null()); ASSERT(!info->code().is_null());
Handle<Code> code = info->code(); Handle<Code> code = info->code();
Handle<JSFunction> function = info->closure(); Handle<JSFunction> function = info->closure();
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
Handle<String>(shared->DebugName()),
shared->start_position(),
info);
if (info->IsOptimizing()) { if (info->IsOptimizing()) {
function->ReplaceCode(*code); function->ReplaceCode(*code);
...@@ -723,10 +720,6 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, ...@@ -723,10 +720,6 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
ASSERT(!info.code().is_null()); ASSERT(!info.code().is_null());
// Function compilation complete. // Function compilation complete.
RecordFunctionCompilation(Logger::FUNCTION_TAG,
literal->debug_name(),
literal->start_position(),
&info);
scope_info = SerializedScopeInfo::Create(info.scope()); scope_info = SerializedScopeInfo::Create(info.scope());
} }
...@@ -737,6 +730,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, ...@@ -737,6 +730,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
info.code(), info.code(),
scope_info); scope_info);
SetFunctionInfo(result, literal, false, script); SetFunctionInfo(result, literal, false, script);
RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
result->set_allows_lazy_compilation(allow_lazy); result->set_allows_lazy_compilation(allow_lazy);
// Set the expected number of properties for instances and return // Set the expected number of properties for instances and return
...@@ -775,28 +769,31 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, ...@@ -775,28 +769,31 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
Handle<String> name, CompilationInfo* info,
int start_position, Handle<SharedFunctionInfo> shared) {
CompilationInfo* info) { // SharedFunctionInfo is passed separately, because if CompilationInfo
// was created using Script object, it will not have it.
// Log the code generation. If source information is available include // Log the code generation. If source information is available include
// script name and line number. Check explicitly whether logging is // script name and line number. Check explicitly whether logging is
// enabled as finding the line number is not free. // enabled as finding the line number is not free.
if (Logger::is_logging() || if (Logger::is_logging() || CpuProfiler::is_profiling()) {
CpuProfiler::is_profiling()) {
Handle<Script> script = info->script(); Handle<Script> script = info->script();
Handle<Code> code = info->code(); Handle<Code> code = info->code();
if (*code == Builtins::builtin(Builtins::LazyCompile)) return;
if (script->name()->IsString()) { if (script->name()->IsString()) {
int line_num = GetScriptLineNumber(script, start_position) + 1; int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
USE(line_num); USE(line_num);
PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code, *code,
*name, *shared,
String::cast(script->name()), String::cast(script->name()),
line_num)); line_num));
} else { } else {
PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code, *code,
*name)); *shared,
shared->DebugName()));
} }
} }
......
...@@ -265,9 +265,8 @@ class Compiler : public AllStatic { ...@@ -265,9 +265,8 @@ class Compiler : public AllStatic {
#endif #endif
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
Handle<String> name, CompilationInfo* info,
int start_position, Handle<SharedFunctionInfo> shared);
CompilationInfo* info);
}; };
......
...@@ -41,6 +41,9 @@ namespace internal { ...@@ -41,6 +41,9 @@ namespace internal {
void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) { void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->AddCode(start, entry, size); code_map->AddCode(start, entry, size);
if (sfi_address != NULL) {
entry->set_shared_id(code_map->GetSFITag(sfi_address));
}
} }
...@@ -54,8 +57,8 @@ void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) { ...@@ -54,8 +57,8 @@ void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
} }
void CodeAliasEventRecord::UpdateCodeMap(CodeMap* code_map) { void SFIMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->AddAlias(start, entry, code_start); code_map->MoveCode(from, to);
} }
......
...@@ -53,13 +53,7 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) ...@@ -53,13 +53,7 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
ticks_buffer_(sizeof(TickSampleEventRecord), ticks_buffer_(sizeof(TickSampleEventRecord),
kTickSamplesBufferChunkSize, kTickSamplesBufferChunkSize,
kTickSamplesBufferChunksCount), kTickSamplesBufferChunksCount),
enqueue_order_(0), enqueue_order_(0) {
known_functions_(new HashMap(AddressesMatch)) {
}
ProfilerEventsProcessor::~ProfilerEventsProcessor() {
delete known_functions_;
} }
...@@ -75,6 +69,7 @@ void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag, ...@@ -75,6 +69,7 @@ void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start; rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, prefix, name); rec->entry = generator_->NewCodeEntry(tag, prefix, name);
rec->size = 1; rec->size = 1;
rec->sfi_address = NULL;
events_buffer_.Enqueue(evt_rec); events_buffer_.Enqueue(evt_rec);
} }
...@@ -84,7 +79,8 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, ...@@ -84,7 +79,8 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
String* resource_name, String* resource_name,
int line_number, int line_number,
Address start, Address start,
unsigned size) { unsigned size,
Address sfi_address) {
if (FilterOutCodeCreateEvent(tag)) return; if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec; CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
...@@ -93,6 +89,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, ...@@ -93,6 +89,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start; rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number); rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
rec->size = size; rec->size = size;
rec->sfi_address = sfi_address;
events_buffer_.Enqueue(evt_rec); events_buffer_.Enqueue(evt_rec);
} }
...@@ -109,6 +106,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, ...@@ -109,6 +106,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start; rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, name); rec->entry = generator_->NewCodeEntry(tag, name);
rec->size = size; rec->size = size;
rec->sfi_address = NULL;
events_buffer_.Enqueue(evt_rec); events_buffer_.Enqueue(evt_rec);
} }
...@@ -125,6 +123,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, ...@@ -125,6 +123,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start; rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, args_count); rec->entry = generator_->NewCodeEntry(tag, args_count);
rec->size = size; rec->size = size;
rec->sfi_address = NULL;
events_buffer_.Enqueue(evt_rec); events_buffer_.Enqueue(evt_rec);
} }
...@@ -150,57 +149,14 @@ void ProfilerEventsProcessor::CodeDeleteEvent(Address from) { ...@@ -150,57 +149,14 @@ void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
} }
void ProfilerEventsProcessor::FunctionCreateEvent(Address alias, void ProfilerEventsProcessor::SFIMoveEvent(Address from, Address to) {
Address start,
int security_token_id) {
CodeEventsContainer evt_rec; CodeEventsContainer evt_rec;
CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_; SFIMoveEventRecord* rec = &evt_rec.SFIMoveEventRecord_;
rec->type = CodeEventRecord::CODE_ALIAS; rec->type = CodeEventRecord::SFI_MOVE;
rec->order = ++enqueue_order_; rec->order = ++enqueue_order_;
rec->start = alias; rec->from = from;
rec->entry = generator_->NewCodeEntry(security_token_id); rec->to = to;
rec->code_start = start;
events_buffer_.Enqueue(evt_rec); events_buffer_.Enqueue(evt_rec);
known_functions_->Lookup(alias, AddressHash(alias), true);
}
void ProfilerEventsProcessor::FunctionMoveEvent(Address from, Address to) {
CodeMoveEvent(from, to);
if (IsKnownFunction(from)) {
known_functions_->Remove(from, AddressHash(from));
known_functions_->Lookup(to, AddressHash(to), true);
}
}
void ProfilerEventsProcessor::FunctionDeleteEvent(Address from) {
CodeDeleteEvent(from);
known_functions_->Remove(from, AddressHash(from));
}
bool ProfilerEventsProcessor::IsKnownFunction(Address start) {
HashMap::Entry* entry =
known_functions_->Lookup(start, AddressHash(start), false);
return entry != NULL;
}
void ProfilerEventsProcessor::ProcessMovedFunctions() {
for (int i = 0; i < moved_functions_.length(); ++i) {
JSFunction* function = moved_functions_[i];
CpuProfiler::FunctionCreateEvent(function);
}
moved_functions_.Clear();
}
void ProfilerEventsProcessor::RememberMovedFunction(JSFunction* function) {
moved_functions_.Add(function);
} }
...@@ -227,13 +183,12 @@ void ProfilerEventsProcessor::AddCurrentStack() { ...@@ -227,13 +183,12 @@ void ProfilerEventsProcessor::AddCurrentStack() {
TickSample* sample = &record.sample; TickSample* sample = &record.sample;
sample->state = Top::current_vm_state(); sample->state = Top::current_vm_state();
sample->pc = reinterpret_cast<Address>(sample); // Not NULL. sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
sample->tos = NULL;
sample->frames_count = 0; sample->frames_count = 0;
for (StackTraceFrameIterator it; for (StackTraceFrameIterator it;
!it.done() && sample->frames_count < TickSample::kMaxFramesCount; !it.done() && sample->frames_count < TickSample::kMaxFramesCount;
it.Advance()) { it.Advance()) {
JavaScriptFrame* frame = it.frame(); sample->stack[sample->frames_count++] = it.frame()->pc();
sample->stack[sample->frames_count++] =
reinterpret_cast<Address>(frame->function());
} }
record.order = enqueue_order_; record.order = enqueue_order_;
ticks_from_vm_buffer_.Enqueue(record); ticks_from_vm_buffer_.Enqueue(record);
...@@ -393,20 +348,38 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, ...@@ -393,20 +348,38 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Heap::empty_string(), Heap::empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo, v8::CpuProfileNode::kNoLineNumberInfo,
code->address(), code->address(),
code->ExecutableSize()); code->ExecutableSize(),
NULL);
} }
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, String* name, Code* code,
String* source, int line) { SharedFunctionInfo* shared,
String* name) {
singleton_->processor_->CodeCreateEvent( singleton_->processor_->CodeCreateEvent(
tag, tag,
name, name,
Heap::empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
shared->address());
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
String* source, int line) {
singleton_->processor_->CodeCreateEvent(
tag,
shared->DebugName(),
source, source,
line, line,
code->address(), code->address(),
code->ExecutableSize()); code->ExecutableSize(),
shared->address());
} }
...@@ -430,44 +403,8 @@ void CpuProfiler::CodeDeleteEvent(Address from) { ...@@ -430,44 +403,8 @@ void CpuProfiler::CodeDeleteEvent(Address from) {
} }
void CpuProfiler::FunctionCreateEvent(JSFunction* function) { void CpuProfiler::SFIMoveEvent(Address from, Address to) {
int security_token_id = TokenEnumerator::kNoSecurityToken; singleton_->processor_->SFIMoveEvent(from, to);
if (function->unchecked_context()->IsContext()) {
security_token_id = singleton_->token_enumerator_->GetTokenId(
function->context()->global_context()->security_token());
}
singleton_->processor_->FunctionCreateEvent(
function->address(),
function->shared()->code()->address(),
security_token_id);
}
void CpuProfiler::ProcessMovedFunctions() {
singleton_->processor_->ProcessMovedFunctions();
}
void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function) {
// This function is called from GC iterators (during Scavenge,
// MC, and MS), so marking bits can be set on objects. That's
// why unchecked accessors are used here.
// The same function can be reported several times.
if (function->unchecked_code() == Builtins::builtin(Builtins::LazyCompile)
|| singleton_->processor_->IsKnownFunction(function->address())) return;
singleton_->processor_->RememberMovedFunction(function);
}
void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
singleton_->processor_->FunctionMoveEvent(from, to);
}
void CpuProfiler::FunctionDeleteEvent(Address from) {
singleton_->processor_->FunctionDeleteEvent(from);
} }
...@@ -539,7 +476,6 @@ void CpuProfiler::StartProcessorIfNotStarted() { ...@@ -539,7 +476,6 @@ void CpuProfiler::StartProcessorIfNotStarted() {
FLAG_log_code = saved_log_code_flag; FLAG_log_code = saved_log_code_flag;
} }
Logger::LogCompiledFunctions(); Logger::LogCompiledFunctions();
Logger::LogFunctionObjects();
Logger::LogAccessorCallbacks(); Logger::LogAccessorCallbacks();
} }
// Enable stack sampling. // Enable stack sampling.
......
...@@ -50,7 +50,7 @@ class TokenEnumerator; ...@@ -50,7 +50,7 @@ class TokenEnumerator;
V(CODE_CREATION, CodeCreateEventRecord) \ V(CODE_CREATION, CodeCreateEventRecord) \
V(CODE_MOVE, CodeMoveEventRecord) \ V(CODE_MOVE, CodeMoveEventRecord) \
V(CODE_DELETE, CodeDeleteEventRecord) \ V(CODE_DELETE, CodeDeleteEventRecord) \
V(CODE_ALIAS, CodeAliasEventRecord) V(SFI_MOVE, SFIMoveEventRecord)
class CodeEventRecord { class CodeEventRecord {
...@@ -73,6 +73,7 @@ class CodeCreateEventRecord : public CodeEventRecord { ...@@ -73,6 +73,7 @@ class CodeCreateEventRecord : public CodeEventRecord {
Address start; Address start;
CodeEntry* entry; CodeEntry* entry;
unsigned size; unsigned size;
Address sfi_address;
INLINE(void UpdateCodeMap(CodeMap* code_map)); INLINE(void UpdateCodeMap(CodeMap* code_map));
}; };
...@@ -95,11 +96,10 @@ class CodeDeleteEventRecord : public CodeEventRecord { ...@@ -95,11 +96,10 @@ class CodeDeleteEventRecord : public CodeEventRecord {
}; };
class CodeAliasEventRecord : public CodeEventRecord { class SFIMoveEventRecord : public CodeEventRecord {
public: public:
Address start; Address from;
CodeEntry* entry; Address to;
Address code_start;
INLINE(void UpdateCodeMap(CodeMap* code_map)); INLINE(void UpdateCodeMap(CodeMap* code_map));
}; };
...@@ -134,7 +134,7 @@ class TickSampleEventRecord BASE_EMBEDDED { ...@@ -134,7 +134,7 @@ class TickSampleEventRecord BASE_EMBEDDED {
class ProfilerEventsProcessor : public Thread { class ProfilerEventsProcessor : public Thread {
public: public:
explicit ProfilerEventsProcessor(ProfileGenerator* generator); explicit ProfilerEventsProcessor(ProfileGenerator* generator);
virtual ~ProfilerEventsProcessor(); virtual ~ProfilerEventsProcessor() {}
// Thread control. // Thread control.
virtual void Run(); virtual void Run();
...@@ -148,7 +148,8 @@ class ProfilerEventsProcessor : public Thread { ...@@ -148,7 +148,8 @@ class ProfilerEventsProcessor : public Thread {
void CodeCreateEvent(Logger::LogEventsAndTags tag, void CodeCreateEvent(Logger::LogEventsAndTags tag,
String* name, String* name,
String* resource_name, int line_number, String* resource_name, int line_number,
Address start, unsigned size); Address start, unsigned size,
Address sfi_address);
void CodeCreateEvent(Logger::LogEventsAndTags tag, void CodeCreateEvent(Logger::LogEventsAndTags tag,
const char* name, const char* name,
Address start, unsigned size); Address start, unsigned size);
...@@ -157,17 +158,12 @@ class ProfilerEventsProcessor : public Thread { ...@@ -157,17 +158,12 @@ class ProfilerEventsProcessor : public Thread {
Address start, unsigned size); Address start, unsigned size);
void CodeMoveEvent(Address from, Address to); void CodeMoveEvent(Address from, Address to);
void CodeDeleteEvent(Address from); void CodeDeleteEvent(Address from);
void FunctionCreateEvent(Address alias, Address start, int security_token_id); void SFIMoveEvent(Address from, Address to);
void FunctionMoveEvent(Address from, Address to);
void FunctionDeleteEvent(Address from);
void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag, void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
const char* prefix, String* name, const char* prefix, String* name,
Address start, unsigned size); Address start, unsigned size);
// Puts current stack into tick sample events buffer. // Puts current stack into tick sample events buffer.
void AddCurrentStack(); void AddCurrentStack();
bool IsKnownFunction(Address start);
void ProcessMovedFunctions();
void RememberMovedFunction(JSFunction* function);
// Tick sample events are filled directly in the buffer of the circular // Tick sample events are filled directly in the buffer of the circular
// queue (because the structure is of fixed width, but usually not all // queue (because the structure is of fixed width, but usually not all
...@@ -188,13 +184,6 @@ class ProfilerEventsProcessor : public Thread { ...@@ -188,13 +184,6 @@ class ProfilerEventsProcessor : public Thread {
bool ProcessTicks(unsigned dequeue_order); bool ProcessTicks(unsigned dequeue_order);
INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag)); INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
INLINE(static bool AddressesMatch(void* key1, void* key2)) {
return key1 == key2;
}
INLINE(static uint32_t AddressHash(Address addr)) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
}
ProfileGenerator* generator_; ProfileGenerator* generator_;
bool running_; bool running_;
...@@ -202,10 +191,6 @@ class ProfilerEventsProcessor : public Thread { ...@@ -202,10 +191,6 @@ class ProfilerEventsProcessor : public Thread {
SamplingCircularQueue ticks_buffer_; SamplingCircularQueue ticks_buffer_;
UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_; UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
unsigned enqueue_order_; unsigned enqueue_order_;
// Used from the VM thread.
HashMap* known_functions_;
List<JSFunction*> moved_functions_;
}; };
} } // namespace v8::internal } } // namespace v8::internal
...@@ -251,23 +236,22 @@ class CpuProfiler { ...@@ -251,23 +236,22 @@ class CpuProfiler {
static void CodeCreateEvent(Logger::LogEventsAndTags tag, static void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, String* name); Code* code, String* name);
static void CodeCreateEvent(Logger::LogEventsAndTags tag, static void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, String* name, Code* code,
SharedFunctionInfo *shared,
String* name);
static void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo *shared,
String* source, int line); String* source, int line);
static void CodeCreateEvent(Logger::LogEventsAndTags tag, static void CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, int args_count); Code* code, int args_count);
static void CodeMovingGCEvent() {} static void CodeMovingGCEvent() {}
static void CodeMoveEvent(Address from, Address to); static void CodeMoveEvent(Address from, Address to);
static void CodeDeleteEvent(Address from); static void CodeDeleteEvent(Address from);
static void FunctionCreateEvent(JSFunction* function);
// Reports function creation in case we had missed it (e.g.
// if it was created from compiled code).
static void FunctionCreateEventFromMove(JSFunction* function);
static void FunctionMoveEvent(Address from, Address to);
static void FunctionDeleteEvent(Address from);
static void GetterCallbackEvent(String* name, Address entry_point); static void GetterCallbackEvent(String* name, Address entry_point);
static void RegExpCodeCreateEvent(Code* code, String* source); static void RegExpCodeCreateEvent(Code* code, String* source);
static void ProcessMovedFunctions();
static void SetterCallbackEvent(String* name, Address entry_point); static void SetterCallbackEvent(String* name, Address entry_point);
static void SFIMoveEvent(Address from, Address to);
static INLINE(bool is_profiling()) { static INLINE(bool is_profiling()) {
return NoBarrier_Load(&is_profiling_); return NoBarrier_Load(&is_profiling_);
......
...@@ -847,9 +847,6 @@ static bool CompileLazyFunction(Handle<JSFunction> function, ...@@ -847,9 +847,6 @@ static bool CompileLazyFunction(Handle<JSFunction> function,
result = CompileLazyHelper(&info, flag); result = CompileLazyHelper(&info, flag);
ASSERT(!result || function->is_compiled()); ASSERT(!result || function->is_compiled());
} }
if (result && function->is_compiled()) {
PROFILE(FunctionCreateEvent(*function));
}
return result; return result;
} }
...@@ -869,9 +866,7 @@ bool CompileLazyInLoop(Handle<JSFunction> function, ...@@ -869,9 +866,7 @@ bool CompileLazyInLoop(Handle<JSFunction> function,
bool CompileOptimized(Handle<JSFunction> function, int osr_ast_id) { bool CompileOptimized(Handle<JSFunction> function, int osr_ast_id) {
CompilationInfo info(function); CompilationInfo info(function);
info.SetOptimizing(osr_ast_id); info.SetOptimizing(osr_ast_id);
bool result = CompileLazyHelper(&info, KEEP_EXCEPTION); return CompileLazyHelper(&info, KEEP_EXCEPTION);
if (result) PROFILE(FunctionCreateEvent(*function));
return result;
} }
......
...@@ -515,7 +515,6 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { ...@@ -515,7 +515,6 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (FLAG_log_gc) HeapProfiler::WriteSample(); if (FLAG_log_gc) HeapProfiler::WriteSample();
if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions();
#endif #endif
return next_gc_likely_to_collect_more; return next_gc_likely_to_collect_more;
...@@ -1350,9 +1349,8 @@ class ScavengingVisitor : public StaticVisitorBase { ...@@ -1350,9 +1349,8 @@ class ScavengingVisitor : public StaticVisitorBase {
HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address())); HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address()));
#if defined(ENABLE_LOGGING_AND_PROFILING) #if defined(ENABLE_LOGGING_AND_PROFILING)
if (Logger::is_logging() || CpuProfiler::is_profiling()) { if (Logger::is_logging() || CpuProfiler::is_profiling()) {
if (target->IsJSFunction()) { if (target->IsSharedFunctionInfo()) {
PROFILE(FunctionMoveEvent(source->address(), target->address())); PROFILE(SFIMoveEvent(source->address(), target->address()));
PROFILE(FunctionCreateEventFromMove(JSFunction::cast(target)));
} }
} }
#endif #endif
......
...@@ -4099,10 +4099,7 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4099,10 +4099,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
if (!FullCodeGenerator::MakeCode(&inner_info)) return false; if (!FullCodeGenerator::MakeCode(&inner_info)) return false;
shared->EnableDeoptimizationSupport(*inner_info.code()); shared->EnableDeoptimizationSupport(*inner_info.code());
Compiler::RecordFunctionCompilation( Compiler::RecordFunctionCompilation(
Logger::FUNCTION_TAG, Logger::FUNCTION_TAG, &inner_info, shared);
Handle<String>(shared->DebugName()),
shared->start_position(),
&inner_info);
} }
// Save the pending call context and type feedback oracle. Set up new ones // Save the pending call context and type feedback oracle. Set up new ones
......
...@@ -300,6 +300,8 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { ...@@ -300,6 +300,8 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
Append("\\,"); Append("\\,");
} else if (c == '\\') { } else if (c == '\\') {
Append("\\\\"); Append("\\\\");
} else if (c == '\"') {
Append("\"\"");
} else { } else {
Append("%lc", c); Append("%lc", c);
} }
......
This diff is collapsed.
...@@ -91,9 +91,7 @@ class LogMessageBuilder; ...@@ -91,9 +91,7 @@ class LogMessageBuilder;
V(CODE_MOVE_EVENT, "code-move") \ V(CODE_MOVE_EVENT, "code-move") \
V(CODE_DELETE_EVENT, "code-delete") \ V(CODE_DELETE_EVENT, "code-delete") \
V(CODE_MOVING_GC, "code-moving-gc") \ V(CODE_MOVING_GC, "code-moving-gc") \
V(FUNCTION_CREATION_EVENT, "function-creation") \ V(SFI_MOVE_EVENT, "sfi-move") \
V(FUNCTION_MOVE_EVENT, "function-move") \
V(FUNCTION_DELETE_EVENT, "function-delete") \
V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \ V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \
V(TICK_EVENT, "tick") \ V(TICK_EVENT, "tick") \
V(REPEAT_META_EVENT, "repeat") \ V(REPEAT_META_EVENT, "repeat") \
...@@ -205,8 +203,15 @@ class Logger { ...@@ -205,8 +203,15 @@ class Logger {
// Emits a code create event. // Emits a code create event.
static void CodeCreateEvent(LogEventsAndTags tag, static void CodeCreateEvent(LogEventsAndTags tag,
Code* code, const char* source); Code* code, const char* source);
static void CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name); static void CodeCreateEvent(LogEventsAndTags tag,
static void CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name, Code* code, String* name);
static void CodeCreateEvent(LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
String* name);
static void CodeCreateEvent(LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
String* source, int line); String* source, int line);
static void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count); static void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
static void CodeMovingGCEvent(); static void CodeMovingGCEvent();
...@@ -216,13 +221,8 @@ class Logger { ...@@ -216,13 +221,8 @@ class Logger {
static void CodeMoveEvent(Address from, Address to); static void CodeMoveEvent(Address from, Address to);
// Emits a code delete event. // Emits a code delete event.
static void CodeDeleteEvent(Address from); static void CodeDeleteEvent(Address from);
// Emits a function object create event.
static void FunctionCreateEvent(JSFunction* function); static void SFIMoveEvent(Address from, Address to);
static void FunctionCreateEventFromMove(JSFunction* function);
// Emits a function move event.
static void FunctionMoveEvent(Address from, Address to);
// Emits a function delete event.
static void FunctionDeleteEvent(Address from);
static void SnapshotPositionEvent(Address addr, int pos); static void SnapshotPositionEvent(Address addr, int pos);
...@@ -273,8 +273,6 @@ class Logger { ...@@ -273,8 +273,6 @@ class Logger {
// Logs all compiled functions found in the heap. // Logs all compiled functions found in the heap.
static void LogCompiledFunctions(); static void LogCompiledFunctions();
// Logs all compiled JSFunction objects found in the heap.
static void LogFunctionObjects();
// Logs all accessor callbacks found in the heap. // Logs all accessor callbacks found in the heap.
static void LogAccessorCallbacks(); static void LogAccessorCallbacks();
// Used for logging stubs found in the snapshot. // Used for logging stubs found in the snapshot.
......
...@@ -2819,9 +2819,8 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj, ...@@ -2819,9 +2819,8 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
ASSERT(!HeapObject::FromAddress(new_addr)->IsCode()); ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
HeapObject* copied_to = HeapObject::FromAddress(new_addr); HeapObject* copied_to = HeapObject::FromAddress(new_addr);
if (copied_to->IsJSFunction()) { if (copied_to->IsSharedFunctionInfo()) {
PROFILE(FunctionMoveEvent(old_addr, new_addr)); PROFILE(SFIMoveEvent(old_addr, new_addr));
PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to)));
} }
HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
...@@ -2912,9 +2911,8 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) { ...@@ -2912,9 +2911,8 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
#endif #endif
HeapObject* copied_to = HeapObject::FromAddress(new_addr); HeapObject* copied_to = HeapObject::FromAddress(new_addr);
if (copied_to->IsJSFunction()) { if (copied_to->IsSharedFunctionInfo()) {
PROFILE(FunctionMoveEvent(old_addr, new_addr)); PROFILE(SFIMoveEvent(old_addr, new_addr));
PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to)));
} }
HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
...@@ -2931,8 +2929,6 @@ void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) { ...@@ -2931,8 +2929,6 @@ void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (obj->IsCode()) { if (obj->IsCode()) {
PROFILE(CodeDeleteEvent(obj->address())); PROFILE(CodeDeleteEvent(obj->address()));
} else if (obj->IsJSFunction()) {
PROFILE(FunctionDeleteEvent(obj->address()));
} }
#endif #endif
} }
......
...@@ -567,13 +567,13 @@ class TickSample { ...@@ -567,13 +567,13 @@ class TickSample {
pc(NULL), pc(NULL),
sp(NULL), sp(NULL),
fp(NULL), fp(NULL),
function(NULL), tos(NULL),
frames_count(0) {} frames_count(0) {}
StateTag state; // The state of the VM. StateTag state; // The state of the VM.
Address pc; // Instruction pointer. Address pc; // Instruction pointer.
Address sp; // Stack pointer. Address sp; // Stack pointer.
Address fp; // Frame pointer. Address fp; // Frame pointer.
Address function; // The last called JS function. Address tos; // Top stack value (*sp).
static const int kMaxFramesCount = 64; static const int kMaxFramesCount = 64;
Address stack[kMaxFramesCount]; // Call stack. Address stack[kMaxFramesCount]; // Call stack.
int frames_count; // Number of captured frames. int frames_count; // Number of captured frames.
......
...@@ -45,16 +45,6 @@ const char* StringsStorage::GetFunctionName(const char* name) { ...@@ -45,16 +45,6 @@ const char* StringsStorage::GetFunctionName(const char* name) {
} }
CodeEntry::CodeEntry(int security_token_id)
: tag_(Logger::FUNCTION_TAG),
name_prefix_(kEmptyNamePrefix),
name_(""),
resource_name_(""),
line_number_(0),
security_token_id_(security_token_id) {
}
CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix, const char* name_prefix,
const char* name, const char* name,
...@@ -66,6 +56,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, ...@@ -66,6 +56,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
name_(name), name_(name),
resource_name_(resource_name), resource_name_(resource_name),
line_number_(line_number), line_number_(line_number),
shared_id_(0),
security_token_id_(security_token_id) { security_token_id_(security_token_id) {
} }
......
...@@ -156,13 +156,18 @@ void CodeEntry::CopyData(const CodeEntry& source) { ...@@ -156,13 +156,18 @@ void CodeEntry::CopyData(const CodeEntry& source) {
uint32_t CodeEntry::GetCallUid() const { uint32_t CodeEntry::GetCallUid() const {
uint32_t hash = ComputeIntegerHash(tag_); uint32_t hash = ComputeIntegerHash(tag_);
hash ^= ComputeIntegerHash( if (shared_id_ != 0) {
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_))); hash ^= ComputeIntegerHash(
hash ^= ComputeIntegerHash( static_cast<uint32_t>(shared_id_));
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_))); } else {
hash ^= ComputeIntegerHash( hash ^= ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_))); static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
hash ^= ComputeIntegerHash(line_number_); hash ^= ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
hash ^= ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
hash ^= ComputeIntegerHash(line_number_);
}
return hash; return hash;
} }
...@@ -170,10 +175,12 @@ uint32_t CodeEntry::GetCallUid() const { ...@@ -170,10 +175,12 @@ uint32_t CodeEntry::GetCallUid() const {
bool CodeEntry::IsSameAs(CodeEntry* entry) const { bool CodeEntry::IsSameAs(CodeEntry* entry) const {
return this == entry return this == entry
|| (tag_ == entry->tag_ || (tag_ == entry->tag_
&& name_prefix_ == entry->name_prefix_ && shared_id_ == entry->shared_id_
&& name_ == entry->name_ && (shared_id_ != 0
&& resource_name_ == entry->resource_name_ || (name_prefix_ == entry->name_prefix_
&& line_number_ == entry->line_number_); && name_ == entry->name_
&& resource_name_ == entry->resource_name_
&& line_number_ == entry->line_number_)));
} }
...@@ -458,23 +465,12 @@ void CpuProfile::Print() { ...@@ -458,23 +465,12 @@ void CpuProfile::Print() {
} }
CodeEntry* const CodeMap::kSfiCodeEntry = NULL;
const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
CodeMap::CodeEntryInfo(NULL, 0); CodeMap::CodeEntryInfo(NULL, 0);
void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) {
CodeTree::Locator locator;
if (tree_.Find(code_start, &locator)) {
const CodeEntryInfo& code_info = locator.value();
if (tree_.Insert(start, &locator)) {
entry->CopyData(*code_info.entry);
locator.set_value(CodeEntryInfo(entry, code_info.size));
}
}
}
CodeEntry* CodeMap::FindEntry(Address addr) { CodeEntry* CodeMap::FindEntry(Address addr) {
CodeTree::Locator locator; CodeTree::Locator locator;
if (tree_.FindGreatestLessThan(addr, &locator)) { if (tree_.FindGreatestLessThan(addr, &locator)) {
...@@ -487,6 +483,22 @@ CodeEntry* CodeMap::FindEntry(Address addr) { ...@@ -487,6 +483,22 @@ CodeEntry* CodeMap::FindEntry(Address addr) {
} }
int CodeMap::GetSFITag(Address addr) {
CodeTree::Locator locator;
// For SFI entries, 'size' field is used to store their IDs.
if (tree_.Find(addr, &locator)) {
const CodeEntryInfo& entry = locator.value();
ASSERT(entry.entry == kSfiCodeEntry);
return entry.size;
} else {
tree_.Insert(addr, &locator);
int tag = next_sfi_tag_++;
locator.set_value(CodeEntryInfo(kSfiCodeEntry, tag));
return tag;
}
}
void CodeMap::CodeTreePrinter::Call( void CodeMap::CodeTreePrinter::Call(
const Address& key, const CodeMap::CodeEntryInfo& value) { const Address& key, const CodeMap::CodeEntryInfo& value) {
OS::Print("%p %5d %s\n", key, value.size, value.entry->name()); OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
...@@ -715,13 +727,6 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, ...@@ -715,13 +727,6 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
} }
CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) {
CodeEntry* entry = new CodeEntry(security_token_id);
code_entries_.Add(entry);
return entry;
}
void CpuProfilesCollection::AddPathToCurrentProfiles( void CpuProfilesCollection::AddPathToCurrentProfiles(
const Vector<CodeEntry*>& path) { const Vector<CodeEntry*>& path) {
// As starting / stopping profiles is rare relatively to this // As starting / stopping profiles is rare relatively to this
...@@ -784,19 +789,10 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { ...@@ -784,19 +789,10 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
if (sample.pc != NULL) { if (sample.pc != NULL) {
*entry++ = code_map_.FindEntry(sample.pc); *entry++ = code_map_.FindEntry(sample.pc);
if (sample.function != NULL) { if (sample.tos != NULL) {
*entry = code_map_.FindEntry(sample.function); *entry = code_map_.FindEntry(sample.tos);
if (*entry != NULL && !(*entry)->is_js_function()) { if (*entry != NULL && !(*entry)->is_js_function()) {
*entry = NULL; *entry = NULL;
} else {
CodeEntry* pc_entry = *entries.start();
if (pc_entry == NULL) {
*entry = NULL;
} else if (pc_entry->is_js_function()) {
// Use function entry in favor of pc entry, as function
// entry has security token.
*entries.start() = NULL;
}
} }
entry++; entry++;
} }
......
...@@ -88,7 +88,6 @@ class StringsStorage { ...@@ -88,7 +88,6 @@ class StringsStorage {
class CodeEntry { class CodeEntry {
public: public:
explicit INLINE(CodeEntry(int security_token_id));
// CodeEntry doesn't own name strings, just references them. // CodeEntry doesn't own name strings, just references them.
INLINE(CodeEntry(Logger::LogEventsAndTags tag, INLINE(CodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix, const char* name_prefix,
...@@ -103,6 +102,8 @@ class CodeEntry { ...@@ -103,6 +102,8 @@ class CodeEntry {
INLINE(const char* name() const) { return name_; } INLINE(const char* name() const) { return name_; }
INLINE(const char* resource_name() const) { return resource_name_; } INLINE(const char* resource_name() const) { return resource_name_; }
INLINE(int line_number() const) { return line_number_; } INLINE(int line_number() const) { return line_number_; }
INLINE(int shared_id() const) { return shared_id_; }
INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
INLINE(int security_token_id() const) { return security_token_id_; } INLINE(int security_token_id() const) { return security_token_id_; }
INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag)); INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
...@@ -119,6 +120,7 @@ class CodeEntry { ...@@ -119,6 +120,7 @@ class CodeEntry {
const char* name_; const char* name_;
const char* resource_name_; const char* resource_name_;
int line_number_; int line_number_;
int shared_id_;
int security_token_id_; int security_token_id_;
DISALLOW_COPY_AND_ASSIGN(CodeEntry); DISALLOW_COPY_AND_ASSIGN(CodeEntry);
...@@ -234,12 +236,12 @@ class CpuProfile { ...@@ -234,12 +236,12 @@ class CpuProfile {
class CodeMap { class CodeMap {
public: public:
CodeMap() { } CodeMap() : next_sfi_tag_(1) { }
INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size)); INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
INLINE(void MoveCode(Address from, Address to)); INLINE(void MoveCode(Address from, Address to));
INLINE(void DeleteCode(Address addr)); INLINE(void DeleteCode(Address addr));
void AddAlias(Address start, CodeEntry* entry, Address code_start);
CodeEntry* FindEntry(Address addr); CodeEntry* FindEntry(Address addr);
int GetSFITag(Address addr);
void Print(); void Print();
...@@ -267,7 +269,11 @@ class CodeMap { ...@@ -267,7 +269,11 @@ class CodeMap {
void Call(const Address& key, const CodeEntryInfo& value); void Call(const Address& key, const CodeEntryInfo& value);
}; };
// Fake CodeEntry pointer to distinguish SFI entries.
static CodeEntry* const kSfiCodeEntry;
CodeTree tree_; CodeTree tree_;
int next_sfi_tag_;
DISALLOW_COPY_AND_ASSIGN(CodeMap); DISALLOW_COPY_AND_ASSIGN(CodeMap);
}; };
......
...@@ -50,7 +50,7 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc, ...@@ -50,7 +50,7 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
i::Address frame3 = NULL) { i::Address frame3 = NULL) {
i::TickSample* sample = proc->TickSampleEvent(); i::TickSample* sample = proc->TickSampleEvent();
sample->pc = frame1; sample->pc = frame1;
sample->function = frame1; sample->tos = frame1;
sample->frames_count = 0; sample->frames_count = 0;
if (frame2 != NULL) { if (frame2 != NULL) {
sample->stack[0] = frame2; sample->stack[0] = frame2;
...@@ -103,7 +103,8 @@ TEST(CodeEvents) { ...@@ -103,7 +103,8 @@ TEST(CodeEvents) {
i::Heap::empty_string(), i::Heap::empty_string(),
0, 0,
ToAddress(0x1000), ToAddress(0x1000),
0x100); 0x100,
ToAddress(0x10000));
processor.CodeCreateEvent(i::Logger::BUILTIN_TAG, processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
"bbb", "bbb",
ToAddress(0x1200), ToAddress(0x1200),
...@@ -116,8 +117,6 @@ TEST(CodeEvents) { ...@@ -116,8 +117,6 @@ TEST(CodeEvents) {
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500)); processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10); processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
processor.CodeDeleteEvent(ToAddress(0x1600)); processor.CodeDeleteEvent(ToAddress(0x1600));
processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000),
TokenEnumerator::kNoSecurityToken);
// Enqueue a tick event to enable code events processing. // Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000)); EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
...@@ -139,9 +138,6 @@ TEST(CodeEvents) { ...@@ -139,9 +138,6 @@ TEST(CodeEvents) {
CHECK_NE(NULL, entry4); CHECK_NE(NULL, entry4);
CHECK_EQ("ddd", entry4->name()); CHECK_EQ("ddd", entry4->name());
CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600))); CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
CodeEntry* entry5 = generator.code_map()->FindEntry(ToAddress(0x1700));
CHECK_NE(NULL, entry5);
CHECK_EQ(aaa_str, entry5->name());
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "v8.h" #include "v8.h"
#include "api.h"
#include "codegen.h" #include "codegen.h"
#include "log.h" #include "log.h"
#include "top.h" #include "top.h"
...@@ -200,16 +201,16 @@ static void InitializeVM() { ...@@ -200,16 +201,16 @@ static void InitializeVM() {
} }
static void CheckJSFunctionAtAddress(const char* func_name, Address addr) { static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
CHECK(i::Heap::Contains(addr)); i::Code* code = function->code();
i::Object* obj = i::HeapObject::FromAddress(addr); return code->contains(addr);
CHECK(obj->IsJSFunction()); }
CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
i::SmartPointer<char> found_name = static bool IsAddressWithinFuncCode(const char* func_name, Address addr) {
i::String::cast( v8::Local<v8::Value> func = env->Global()->Get(v8_str(func_name));
JSFunction::cast( CHECK(func->IsFunction());
obj)->shared()->name())->ToCString(); JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
CHECK_EQ(func_name, *found_name); return IsAddressWithinFuncCode(js_func, addr);
} }
...@@ -309,8 +310,8 @@ TEST(CFromJSStackTrace) { ...@@ -309,8 +310,8 @@ TEST(CFromJSStackTrace) {
// Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
CHECK_GT(sample.frames_count, base + 1); CHECK_GT(sample.frames_count, base + 1);
CheckJSFunctionAtAddress("JSFuncDoTrace", sample.stack[base + 0]); CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0]));
CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 1]); CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1]));
} }
...@@ -351,9 +352,6 @@ TEST(PureJSStackTrace) { ...@@ -351,9 +352,6 @@ TEST(PureJSStackTrace) {
// DoTraceHideCEntryFPAddress(EBP) [native] // DoTraceHideCEntryFPAddress(EBP) [native]
// StackTracer::Trace // StackTracer::Trace
// //
// The last JS function called. It is only visible through
// sample.function, as its return address is above captured EBP value.
CheckJSFunctionAtAddress("JSFuncDoTrace", sample.function);
// The VM state tracking keeps track of external callbacks and puts // The VM state tracking keeps track of external callbacks and puts
// them at the top of the sample stack. // them at the top of the sample stack.
...@@ -363,8 +361,8 @@ TEST(PureJSStackTrace) { ...@@ -363,8 +361,8 @@ TEST(PureJSStackTrace) {
// Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
CHECK_GT(sample.frames_count, base + 1); CHECK_GT(sample.frames_count, base + 1);
CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 0]); CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0]));
CheckJSFunctionAtAddress("OuterJSTrace", sample.stack[base + 1]); CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1]));
} }
......
...@@ -1053,10 +1053,10 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) { ...@@ -1053,10 +1053,10 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) {
// Skip size. // Skip size.
ref_s = strchr(ref_s, ',') + 1; ref_s = strchr(ref_s, ',') + 1;
new_s = strchr(new_s, ',') + 1; new_s = strchr(new_s, ',') + 1;
int ref_len = StrChrLen(ref_s, '\n'); CHECK_EQ('"', ref_s[0]);
int new_len = StrChrLen(new_s, '\n'); CHECK_EQ('"', new_s[0]);
// If reference is anonymous (""), it's OK to have anything in new. int ref_len = StrChrLen(ref_s + 1, '\"');
if (ref_len == 2) return true; int new_len = StrChrLen(new_s + 1, '\"');
// A special case for ErrorPrototype. Haven't yet figured out why they // A special case for ErrorPrototype. Haven't yet figured out why they
// are different. // are different.
const char* error_prototype = "\"ErrorPrototype"; const char* error_prototype = "\"ErrorPrototype";
...@@ -1074,21 +1074,6 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) { ...@@ -1074,21 +1074,6 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) {
return true; return true;
} }
} }
// Code objects can change their optimizability: code object may start
// as optimizable, but later be discovered to be actually not optimizable.
// Alas, we don't record this info as of now, so we allow cases when
// ref is thought to be optimizable while traverse finds it to be
// not optimizable.
if (ref_s[1] == '~') { // Code object used to be optimizable
if (new_s[1] == ' ') { // ...but later was set unoptimizable.
CHECK_EQ('"', ref_s[0]);
CHECK_EQ('"', new_s[0]);
ref_s += 2; // Cut the leading quote and the marker
ref_len -= 2;
new_s += 1; // Cut the leading quote only.
new_len -= 1;
}
}
return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0; return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0;
} }
......
...@@ -600,13 +600,13 @@ TEST(RecordTickSample) { ...@@ -600,13 +600,13 @@ TEST(RecordTickSample) {
// -> ccc -> aaa - sample3 // -> ccc -> aaa - sample3
TickSample sample1; TickSample sample1;
sample1.pc = ToAddress(0x1600); sample1.pc = ToAddress(0x1600);
sample1.function = ToAddress(0x1500); sample1.tos = ToAddress(0x1500);
sample1.stack[0] = ToAddress(0x1510); sample1.stack[0] = ToAddress(0x1510);
sample1.frames_count = 1; sample1.frames_count = 1;
generator.RecordTickSample(sample1); generator.RecordTickSample(sample1);
TickSample sample2; TickSample sample2;
sample2.pc = ToAddress(0x1925); sample2.pc = ToAddress(0x1925);
sample2.function = ToAddress(0x1900); sample2.tos = ToAddress(0x1900);
sample2.stack[0] = ToAddress(0x1780); sample2.stack[0] = ToAddress(0x1780);
sample2.stack[1] = ToAddress(0x10000); // non-existent. sample2.stack[1] = ToAddress(0x10000); // non-existent.
sample2.stack[2] = ToAddress(0x1620); sample2.stack[2] = ToAddress(0x1620);
...@@ -614,7 +614,7 @@ TEST(RecordTickSample) { ...@@ -614,7 +614,7 @@ TEST(RecordTickSample) {
generator.RecordTickSample(sample2); generator.RecordTickSample(sample2);
TickSample sample3; TickSample sample3;
sample3.pc = ToAddress(0x1510); sample3.pc = ToAddress(0x1510);
sample3.function = ToAddress(0x1500); sample3.tos = ToAddress(0x1500);
sample3.stack[0] = ToAddress(0x1910); sample3.stack[0] = ToAddress(0x1910);
sample3.stack[1] = ToAddress(0x1610); sample3.stack[1] = ToAddress(0x1610);
sample3.frames_count = 2; sample3.frames_count = 2;
......
...@@ -3,11 +3,9 @@ shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000 ...@@ -3,11 +3,9 @@ shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
profiler,"begin",1 profiler,"begin",1
code-creation,Stub,0x424260,348,"CompareStub_GE" code-creation,Stub,0x424260,348,"CompareStub_GE"
code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188" code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
function-creation,0x2d11b8,0x2a8100 code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17" tick,0x424284,0xbfffeea0,0x480600,0,0x2aaaa5
function-creation,0x2d0f7c,0x480100 tick,0x42429f,0xbfffed88,0x480600,0,0x2aacb4
tick,0x424284,0xbfffeea0,0x2d0f7c,0,0x2aaaa5
tick,0x42429f,0xbfffed88,0x2d0f7c,0,0x2aacb4
tick,0x48063d,0xbfffec7c,0x2d0f7c,0,0x2aaec6 tick,0x48063d,0xbfffec7c,0x2d0f7c,0,0x2aaec6
profiler,"end" profiler,"end"
...@@ -311,7 +311,7 @@ class CodeLogReader(object): ...@@ -311,7 +311,7 @@ class CodeLogReader(object):
r"code-info,([^,]+),(\d+)") r"code-info,([^,]+),(\d+)")
_CODE_CREATE_RE = re.compile( _CODE_CREATE_RE = re.compile(
r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(\d+))?") r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(0x[a-f0-9]+),([~*])?)?(?:,(\d+))?")
_CODE_MOVE_RE = re.compile( _CODE_MOVE_RE = re.compile(
r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)") r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)")
...@@ -358,12 +358,18 @@ class CodeLogReader(object): ...@@ -358,12 +358,18 @@ class CodeLogReader(object):
name = self.address_to_snapshot_name[start_address] name = self.address_to_snapshot_name[start_address]
origin = JS_SNAPSHOT_ORIGIN origin = JS_SNAPSHOT_ORIGIN
else: else:
name = "%s:%s" % (match.group(1), match.group(4)) tag = match.group(1)
optimization_status = match.group(6)
func_name = match.group(4)
if optimization_status:
name = "%s:%s%s" % (tag, optimization_status, func_name)
else:
name = "%s:%s" % (tag, func_name)
origin = JS_ORIGIN origin = JS_ORIGIN
if self.is_snapshot: if self.is_snapshot:
origin_offset = 0 origin_offset = 0
else: else:
origin_offset = int(match.group(5)) origin_offset = int(match.group(7))
code = Code(name, start_address, end_address, origin, origin_offset) code = Code(name, start_address, end_address, origin, origin_offset)
conficting_code = self.code_map.Find(start_address) conficting_code = self.code_map.Find(start_address)
if conficting_code: if conficting_code:
......
...@@ -38,11 +38,6 @@ function Profile() { ...@@ -38,11 +38,6 @@ function Profile() {
this.bottomUpTree_ = new CallTree(); this.bottomUpTree_ = new CallTree();
}; };
/**
* Version of profiler log.
*/
Profile.VERSION = 2;
/** /**
* Returns whether a function with the specified name must be skipped. * Returns whether a function with the specified name must be skipped.
...@@ -68,6 +63,18 @@ Profile.Operation = { ...@@ -68,6 +63,18 @@ Profile.Operation = {
}; };
/**
* Enum for code state regarding its dynamic optimization.
*
* @enum {number}
*/
Profile.CodeState = {
COMPILED: 0,
OPTIMIZABLE: 1,
OPTIMIZED: 2
};
/** /**
* Called whenever the specified operation has failed finding a function * Called whenever the specified operation has failed finding a function
* containing the specified address. Should be overriden by subclasses. * containing the specified address. Should be overriden by subclasses.
...@@ -134,17 +141,30 @@ Profile.prototype.addCode = function( ...@@ -134,17 +141,30 @@ Profile.prototype.addCode = function(
/** /**
* Creates an alias entry for a code entry. * Registers dynamic (JIT-compiled) code entry.
* *
* @param {number} aliasAddr Alias address. * @param {string} type Code entry type.
* @param {number} addr Code entry address. * @param {string} name Code entry name.
*/ * @param {number} start Starting address.
Profile.prototype.addCodeAlias = function( * @param {number} size Code entry size.
aliasAddr, addr) { * @param {number} funcAddr Shared function object address.
var entry = this.codeMap_.findDynamicEntryByStartAddress(addr); * @param {Profile.CodeState} state Optimization state.
if (entry) { */
this.codeMap_.addCode(aliasAddr, entry); Profile.prototype.addFuncCode = function(
type, name, start, size, funcAddr, state) {
// As code and functions are in the same address space,
// it is safe to put them in a single code map.
var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
if (!func) {
func = new Profile.FunctionEntry(name);
this.codeMap_.addCode(funcAddr, func);
} else if (func.name !== name) {
// Function object has been overwritten with a new one.
func.name = name;
} }
var entry = new Profile.DynamicFuncCodeEntry(size, type, func, state);
this.codeMap_.addCode(start, entry);
return entry;
}; };
...@@ -183,25 +203,13 @@ Profile.prototype.deleteCode = function(start) { ...@@ -183,25 +203,13 @@ Profile.prototype.deleteCode = function(start) {
* @param {number} from Current code entry address. * @param {number} from Current code entry address.
* @param {number} to New code entry address. * @param {number} to New code entry address.
*/ */
Profile.prototype.safeMoveDynamicCode = function(from, to) { Profile.prototype.moveFunc = function(from, to) {
if (this.codeMap_.findDynamicEntryByStartAddress(from)) { if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
this.codeMap_.moveCode(from, to); this.codeMap_.moveCode(from, to);
} }
}; };
/**
* Reports about deletion of a dynamic code entry.
*
* @param {number} start Starting address.
*/
Profile.prototype.safeDeleteDynamicCode = function(start) {
if (this.codeMap_.findDynamicEntryByStartAddress(start)) {
this.codeMap_.deleteCode(start);
}
};
/** /**
* Retrieves a code entry by an address. * Retrieves a code entry by an address.
* *
...@@ -383,14 +391,7 @@ Profile.DynamicCodeEntry = function(size, type, name) { ...@@ -383,14 +391,7 @@ Profile.DynamicCodeEntry = function(size, type, name) {
* Returns node name. * Returns node name.
*/ */
Profile.DynamicCodeEntry.prototype.getName = function() { Profile.DynamicCodeEntry.prototype.getName = function() {
var name = this.name; return this.type + ': ' + this.name;
if (name.length == 0) {
name = '<anonymous>';
} else if (name.charAt(0) == ' ') {
// An anonymous function with location: " aaa.js:10".
name = '<anonymous>' + name;
}
return this.type + ': ' + name;
}; };
...@@ -403,9 +404,73 @@ Profile.DynamicCodeEntry.prototype.getRawName = function() { ...@@ -403,9 +404,73 @@ Profile.DynamicCodeEntry.prototype.getRawName = function() {
Profile.DynamicCodeEntry.prototype.isJSFunction = function() { Profile.DynamicCodeEntry.prototype.isJSFunction = function() {
return this.type == "Function" || return false;
this.type == "LazyCompile" || };
this.type == "Script";
/**
* Creates a dynamic code entry.
*
* @param {number} size Code size.
* @param {string} type Code type.
* @param {Profile.FunctionEntry} func Shared function entry.
* @param {Profile.CodeState} state Code optimization state.
* @constructor
*/
Profile.DynamicFuncCodeEntry = function(size, type, func, state) {
CodeMap.CodeEntry.call(this, size);
this.type = type;
this.func = func;
this.state = state;
};
Profile.DynamicFuncCodeEntry.STATE_PREFIX = ["", "~", "*"];
/**
* Returns node name.
*/
Profile.DynamicFuncCodeEntry.prototype.getName = function() {
var name = this.func.getName();
return this.type + ': ' + Profile.DynamicFuncCodeEntry.STATE_PREFIX[this.state] + name;
};
/**
* Returns raw node name (without type decoration).
*/
Profile.DynamicFuncCodeEntry.prototype.getRawName = function() {
return this.func.getName();
};
Profile.DynamicFuncCodeEntry.prototype.isJSFunction = function() {
return true;
};
/**
* Creates a shared function object entry.
*
* @param {string} name Function name.
* @constructor
*/
Profile.FunctionEntry = function(name) {
CodeMap.CodeEntry.call(this, 0, name);
};
/**
* Returns node name.
*/
Profile.FunctionEntry.prototype.getName = function() {
var name = this.name;
if (name.length == 0) {
name = '<anonymous>';
} else if (name.charAt(0) == ' ') {
// An anonymous function with location: " aaa.js:10".
name = '<anonymous>' + name;
}
return name;
}; };
......
...@@ -57,10 +57,23 @@ function readFile(fileName) { ...@@ -57,10 +57,23 @@ function readFile(fileName) {
} }
/**
* Parser for dynamic code optimization state.
*/
function parseState(s) {
switch (s) {
case "": return Profile.CodeState.COMPILED;
case "~": return Profile.CodeState.OPTIMIZABLE;
case "*": return Profile.CodeState.OPTIMIZED;
}
throw new Error("unknown code state: " + s);
}
function SnapshotLogProcessor() { function SnapshotLogProcessor() {
LogReader.call(this, { LogReader.call(this, {
'code-creation': { 'code-creation': {
parsers: [null, parseInt, parseInt, null], parsers: [null, parseInt, parseInt, null, 'var-args'],
processor: this.processCodeCreation }, processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt], 'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove }, processor: this.processCodeMove },
...@@ -69,6 +82,7 @@ function SnapshotLogProcessor() { ...@@ -69,6 +82,7 @@ function SnapshotLogProcessor() {
'function-creation': null, 'function-creation': null,
'function-move': null, 'function-move': null,
'function-delete': null, 'function-delete': null,
'sfi-move': null,
'snapshot-pos': { parsers: [parseInt, parseInt], 'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition }}); processor: this.processSnapshotPosition }});
...@@ -93,8 +107,14 @@ inherits(SnapshotLogProcessor, LogReader); ...@@ -93,8 +107,14 @@ inherits(SnapshotLogProcessor, LogReader);
SnapshotLogProcessor.prototype.processCodeCreation = function( SnapshotLogProcessor.prototype.processCodeCreation = function(
type, start, size, name) { type, start, size, name, maybe_func) {
var entry = this.profile_.addCode(type, name, start, size); if (maybe_func.length) {
var funcAddr = parseInt(maybe_func[0]);
var state = parseState(maybe_func[1]);
this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
} else {
this.profile_.addCode(type, name, start, size);
}
}; };
...@@ -131,18 +151,14 @@ function TickProcessor( ...@@ -131,18 +151,14 @@ function TickProcessor(
'shared-library': { parsers: [null, parseInt, parseInt], 'shared-library': { parsers: [null, parseInt, parseInt],
processor: this.processSharedLibrary }, processor: this.processSharedLibrary },
'code-creation': { 'code-creation': {
parsers: [null, parseInt, parseInt, null], parsers: [null, parseInt, parseInt, null, 'var-args'],
processor: this.processCodeCreation }, processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt], 'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove }, processor: this.processCodeMove },
'code-delete': { parsers: [parseInt], 'code-delete': { parsers: [parseInt],
processor: this.processCodeDelete }, processor: this.processCodeDelete },
'function-creation': { parsers: [parseInt, parseInt], 'sfi-move': { parsers: [parseInt, parseInt],
processor: this.processFunctionCreation },
'function-move': { parsers: [parseInt, parseInt],
processor: this.processFunctionMove }, processor: this.processFunctionMove },
'function-delete': { parsers: [parseInt],
processor: this.processFunctionDelete },
'snapshot-pos': { parsers: [parseInt, parseInt], 'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition }, processor: this.processSnapshotPosition },
'tick': { parsers: [parseInt, parseInt, parseInt, parseInt, 'var-args'], 'tick': { parsers: [parseInt, parseInt, parseInt, parseInt, 'var-args'],
...@@ -155,6 +171,9 @@ function TickProcessor( ...@@ -155,6 +171,9 @@ function TickProcessor(
processor: this.processJSProducer }, processor: this.processJSProducer },
// Ignored events. // Ignored events.
'profiler': null, 'profiler': null,
'function-creation': null,
'function-move': null,
'function-delete': null,
'heap-sample-stats': null, 'heap-sample-stats': null,
'heap-sample-item': null, 'heap-sample-item': null,
'heap-js-cons-item': null, 'heap-js-cons-item': null,
...@@ -285,9 +304,15 @@ TickProcessor.prototype.processSharedLibrary = function( ...@@ -285,9 +304,15 @@ TickProcessor.prototype.processSharedLibrary = function(
TickProcessor.prototype.processCodeCreation = function( TickProcessor.prototype.processCodeCreation = function(
type, start, size, name) { type, start, size, name, maybe_func) {
name = this.deserializedEntriesNames_[start] || name; name = this.deserializedEntriesNames_[start] || name;
var entry = this.profile_.addCode(type, name, start, size); if (maybe_func.length) {
var funcAddr = parseInt(maybe_func[0]);
var state = parseState(maybe_func[1]);
this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
} else {
this.profile_.addCode(type, name, start, size);
}
}; };
...@@ -301,19 +326,8 @@ TickProcessor.prototype.processCodeDelete = function(start) { ...@@ -301,19 +326,8 @@ TickProcessor.prototype.processCodeDelete = function(start) {
}; };
TickProcessor.prototype.processFunctionCreation = function(
functionAddr, codeAddr) {
this.profile_.addCodeAlias(functionAddr, codeAddr);
};
TickProcessor.prototype.processFunctionMove = function(from, to) { TickProcessor.prototype.processFunctionMove = function(from, to) {
this.profile_.safeMoveDynamicCode(from, to); this.profile_.moveFunc(from, to);
};
TickProcessor.prototype.processFunctionDelete = function(start) {
this.profile_.safeDeleteDynamicCode(start);
}; };
...@@ -330,7 +344,7 @@ TickProcessor.prototype.includeTick = function(vmState) { ...@@ -330,7 +344,7 @@ TickProcessor.prototype.includeTick = function(vmState) {
}; };
TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) { TickProcessor.prototype.processTick = function(pc, sp, tos, vmState, stack) {
this.ticks_.total++; this.ticks_.total++;
if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++; if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++;
if (!this.includeTick(vmState)) { if (!this.includeTick(vmState)) {
...@@ -338,19 +352,14 @@ TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) { ...@@ -338,19 +352,14 @@ TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) {
return; return;
} }
if (func) { if (tos) {
var funcEntry = this.profile_.findEntry(func); var funcEntry = this.profile_.findEntry(tos);
if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) { if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
func = 0; tos = 0;
} else {
var currEntry = this.profile_.findEntry(pc);
if (!currEntry || !currEntry.isJSFunction || currEntry.isJSFunction()) {
func = 0;
}
} }
} }
this.profile_.recordTick(this.processStack(pc, func, stack)); this.profile_.recordTick(this.processStack(pc, tos, stack));
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment