#ifdef ENABLE_LOGGING_AND_PROFILING
#include "frames-inl.h"
+#include "hashmap.h"
#include "log-inl.h"
#include "../include/v8-profiler.h"
ticks_buffer_(sizeof(TickSampleEventRecord),
kTickSamplesBufferChunkSize,
kTickSamplesBufferChunksCount),
- enqueue_order_(0) {
+ enqueue_order_(0),
+ known_functions_(new HashMap(AddressesMatch)) {
+}
+
+
+ProfilerEventsProcessor::~ProfilerEventsProcessor() {
+ delete known_functions_;
}
rec->entry = generator_->NewCodeEntry(security_token_id);
rec->code_start = start;
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 CpuProfiler::FunctionCreateEventFromMove(JSFunction* function,
+ HeapObject* source) {
+ // 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;
+
+ int security_token_id = TokenEnumerator::kNoSecurityToken;
+ // In debug mode, assertions may fail for contexts,
+ // and we can live without security tokens in debug mode.
+#ifndef DEBUG
+ if (function->unchecked_context()->IsContext()) {
+ security_token_id = singleton_->token_enumerator_->GetTokenId(
+ function->context()->global_context()->security_token());
+ }
+ // Security token may not be moved yet.
+ if (security_token_id == TokenEnumerator::kNoSecurityToken) {
+ JSFunction* old_function = reinterpret_cast<JSFunction*>(source);
+ if (old_function->unchecked_context()->IsContext()) {
+ security_token_id = singleton_->token_enumerator_->GetTokenId(
+ old_function->context()->global_context()->security_token());
+ }
+ }
+#endif
+ singleton_->processor_->FunctionCreateEvent(
+ function->address(),
+ function->unchecked_code()->address(),
+ security_token_id);
+}
+
+
void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
singleton_->processor_->FunctionMoveEvent(from, to);
}
processor_->Start();
// Enumerate stuff we already have in the heap.
if (Heap::HasBeenSetup()) {
- Logger::LogCodeObjects();
+ if (!FLAG_prof_browser_mode) {
+ bool saved_log_code_flag = FLAG_log_code;
+ FLAG_log_code = true;
+ Logger::LogCodeObjects();
+ FLAG_log_code = saved_log_code_flag;
+ }
Logger::LogCompiledFunctions();
Logger::LogFunctionObjects();
Logger::LogAccessorCallbacks();
class CodeMap;
class CpuProfile;
class CpuProfilesCollection;
+class HashMap;
class ProfileGenerator;
class TokenEnumerator;
class ProfilerEventsProcessor : public Thread {
public:
explicit ProfilerEventsProcessor(ProfileGenerator* generator);
- virtual ~ProfilerEventsProcessor() { }
+ virtual ~ProfilerEventsProcessor();
// Thread control.
virtual void Run();
Address start, unsigned size);
// Puts current stack into tick sample events buffer.
void AddCurrentStack();
+ bool IsKnownFunction(Address start);
// Tick sample events are filled directly in the buffer of the circular
// queue (because the structure is of fixed width, but usually not all
bool ProcessTicks(unsigned dequeue_order);
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_;
bool running_;
SamplingCircularQueue ticks_buffer_;
UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
unsigned enqueue_order_;
+
+ // Used from the VM thread.
+ HashMap* known_functions_;
};
} } // namespace v8::internal
static void CodeMoveEvent(Address from, Address to);
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,
+ HeapObject* source);
static void FunctionMoveEvent(Address from, Address to);
static void FunctionDeleteEvent(Address from);
static void GetterCallbackEvent(String* name, Address entry_point);
RecordCopiedObject(target);
#endif
HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address()));
-
+#if defined(ENABLE_LOGGING_AND_PROFILING)
+ if (Logger::is_logging() || CpuProfiler::is_profiling()) {
+ if (target->IsJSFunction()) {
+ PROFILE(FunctionMoveEvent(source->address(), target->address()));
+ PROFILE(FunctionCreateEventFromMove(JSFunction::cast(target), source));
+ }
+ }
+#endif
return target;
}
void Logger::FunctionCreateEvent(JSFunction* function) {
#ifdef ENABLE_LOGGING_AND_PROFILING
+ // This function can be 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.
static Address prev_code = NULL;
if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("%s,", log_events_[FUNCTION_CREATION_EVENT]);
msg.AppendAddress(function->address());
msg.Append(',');
- msg.AppendAddress(function->code()->address(), prev_code);
- prev_code = function->code()->address();
+ msg.AppendAddress(function->unchecked_code()->address(), prev_code);
+ prev_code = function->unchecked_code()->address();
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
+void Logger::FunctionCreateEventFromMove(JSFunction* function,
+ HeapObject*) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ if (function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile)) {
+ FunctionCreateEvent(function);
+ }
+#endif
+}
+
+
void Logger::FunctionMoveEvent(Address from, Address to) {
#ifdef ENABLE_LOGGING_AND_PROFILING
MoveEventInternal(FUNCTION_MOVE_EVENT, from, to);
static void CodeDeleteEvent(Address from);
// Emits a function object create event.
static void FunctionCreateEvent(JSFunction* function);
+ static void FunctionCreateEventFromMove(JSFunction* function,
+ HeapObject*);
// Emits a function move event.
static void FunctionMoveEvent(Address from, Address to);
// Emits a function delete event.
HeapObject* copied_to = HeapObject::FromAddress(new_addr);
if (copied_to->IsJSFunction()) {
PROFILE(FunctionMoveEvent(old_addr, new_addr));
+ PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to), obj));
}
HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
HeapObject* copied_to = HeapObject::FromAddress(new_addr);
if (copied_to->IsJSFunction()) {
PROFILE(FunctionMoveEvent(old_addr, new_addr));
+ PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to), obj));
}
HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
}
-
#define SMI_ACCESSORS(holder, name, offset) \
int holder::name() { \
Object* value = READ_FIELD(this, offset); \
uint32_t CodeEntry::GetCallUid() const {
uint32_t hash = ComputeIntegerHash(tag_);
- hash ^= static_cast<int32_t>(reinterpret_cast<intptr_t>(name_prefix_));
- hash ^= static_cast<int32_t>(reinterpret_cast<intptr_t>(name_));
- hash ^= static_cast<int32_t>(reinterpret_cast<intptr_t>(resource_name_));
- hash ^= static_cast<int32_t>(line_number_);
+ hash ^= ComputeIntegerHash(
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
+ 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;
}
CodeTree::Locator locator;
if (tree_.Find(code_start, &locator)) {
const CodeEntryInfo& code_info = locator.value();
- entry->CopyData(*code_info.entry);
- tree_.Insert(start, &locator);
- locator.set_value(CodeEntryInfo(entry, code_info.size));
+ if (tree_.Insert(start, &locator)) {
+ entry->CopyData(*code_info.entry);
+ locator.set_value(CodeEntryInfo(entry, code_info.size));
+ }
}
}
}
static uint32_t AddressHash(Address addr) {
- return static_cast<int32_t>(reinterpret_cast<intptr_t>(addr));
+ return ComputeIntegerHash(
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
}
bool initial_fill_mode_;
};
uint32_t Hash(HeapObject* object) {
- return static_cast<uint32_t>(reinterpret_cast<intptr_t>(object));
+ return ComputeIntegerHash(
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object)));
}
static bool HeapObjectsMatch(void* key1, void* key2) { return key1 == key2; }
}
INLINE(static uint32_t ObjectHash(const void* key)) {
- return static_cast<int32_t>(reinterpret_cast<intptr_t>(key));
+ return ComputeIntegerHash(
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)));
}
void EnumerateNodes();
Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
- return GetCodeWithFlags(flags, name);
+ Object* result = GetCodeWithFlags(flags, name);
+ if (!result->IsFailure()) {
+ PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(result), name));
+ }
+ return result;
}
Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
- return GetCodeWithFlags(flags, name);
+ Object* result = GetCodeWithFlags(flags, name);
+ if (!result->IsFailure()) {
+ PROFILE(
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(result), name));
+ }
+ return result;
}
Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
- return GetCodeWithFlags(flags, name);
+ Object* result = GetCodeWithFlags(flags, name);
+ if (!result->IsFailure()) {
+ PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(result), name));
+ }
+ return result;
}
Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
- return GetCodeWithFlags(flags, name);
+ Object* result = GetCodeWithFlags(flags, name);
+ if (!result->IsFailure()) {
+ PROFILE(
+ CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(result), name));
+ }
+ return result;
}