Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index 4c2a330898145beadb4d226657fe52ac62516eaa..d2ae3deb2c0d00010fb4906f133b585e07fa770d 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -28,6 +28,7 @@ |
#ifdef ENABLE_LOGGING_AND_PROFILING |
#include "v8.h" |
+#include "global-handles.h" |
#include "profile-generator-inl.h" |
@@ -37,10 +38,68 @@ namespace v8 { |
namespace internal { |
+TokenEnumerator::TokenEnumerator() |
+ : token_locations_(4), |
+ token_removed_(4) { |
+} |
+ |
+ |
+TokenEnumerator::~TokenEnumerator() { |
+ for (int i = 0; i < token_locations_.length(); ++i) { |
+ if (!token_removed_[i]) { |
+ GlobalHandles::ClearWeakness(token_locations_[i]); |
+ GlobalHandles::Destroy(token_locations_[i]); |
+ } |
+ } |
+} |
+ |
+ |
+int TokenEnumerator::GetTokenId(Object* token) { |
+ if (token == NULL) return CodeEntry::kNoSecurityToken; |
+ for (int i = 0; i < token_locations_.length(); ++i) { |
+ if (*token_locations_[i] == token && !token_removed_[i]) return i; |
+ } |
+ Handle<Object> handle = GlobalHandles::Create(token); |
+ // handle.location() points to a memory cell holding a pointer |
+ // to a token object in the V8's heap. |
+ GlobalHandles::MakeWeak(handle.location(), this, TokenRemovedCallback); |
+ token_locations_.Add(handle.location()); |
+ token_removed_.Add(false); |
+ return token_locations_.length() - 1; |
+} |
+ |
+ |
+void TokenEnumerator::TokenRemovedCallback(v8::Persistent<v8::Value> handle, |
+ void* parameter) { |
+ reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved( |
+ Utils::OpenHandle(*handle).location()); |
+} |
+ |
+ |
+void TokenEnumerator::TokenRemoved(Object** token_location) { |
+ for (int i = 0; i < token_locations_.length(); ++i) { |
+ if (token_locations_[i] == token_location && !token_removed_[i]) { |
+ token_removed_[i] = true; |
+ return; |
+ } |
+ } |
+} |
+ |
+ |
const char* CodeEntry::kEmptyNamePrefix = ""; |
unsigned CodeEntry::next_call_uid_ = 1; |
+void CodeEntry::CopyData(const CodeEntry& source) { |
+ call_uid_ = source.call_uid_; |
+ tag_ = source.tag_; |
+ name_prefix_ = source.name_prefix_; |
+ name_ = source.name_; |
+ resource_name_ = source.resource_name_; |
+ line_number_ = source.line_number_; |
+} |
+ |
+ |
ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
HashMap::Entry* map_entry = |
children_.Lookup(entry, CodeEntryHash(entry), false); |
@@ -73,11 +132,12 @@ double ProfileNode::GetTotalMillis() const { |
void ProfileNode::Print(int indent) { |
- OS::Print("%5u %5u %*c %s%s", |
+ OS::Print("%5u %5u %*c %s%s [%d]", |
total_ticks_, self_ticks_, |
indent, ' ', |
entry_->name_prefix(), |
- entry_->name()); |
+ entry_->name(), |
+ entry_->security_token_id()); |
if (entry_->resource_name()[0] != '\0') |
OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); |
OS::Print("\n"); |
@@ -93,6 +153,8 @@ namespace { |
class DeleteNodesCallback { |
public: |
+ void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
+ |
void AfterAllChildrenTraversed(ProfileNode* node) { |
delete node; |
} |
@@ -104,14 +166,19 @@ class DeleteNodesCallback { |
ProfileTree::ProfileTree() |
- : root_entry_(Logger::FUNCTION_TAG, "", "(root)", "", 0), |
+ : root_entry_(Logger::FUNCTION_TAG, |
+ "", |
+ "(root)", |
+ "", |
+ 0, |
+ CodeEntry::kNoSecurityToken), |
root_(new ProfileNode(this, &root_entry_)) { |
} |
ProfileTree::~ProfileTree() { |
DeleteNodesCallback cb; |
- TraverseDepthFirstPostOrder(&cb); |
+ TraverseDepthFirst(&cb); |
} |
@@ -141,6 +208,70 @@ void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { |
} |
+namespace { |
+ |
+struct NodesPair { |
+ NodesPair(ProfileNode* src, ProfileNode* dst) |
+ : src(src), dst(dst) { } |
+ ProfileNode* src; |
+ ProfileNode* dst; |
+}; |
+ |
+ |
+class FilteredCloneCallback { |
+ public: |
+ explicit FilteredCloneCallback(ProfileNode* dst_root, int security_token_id) |
+ : stack_(10), |
+ security_token_id_(security_token_id) { |
+ stack_.Add(NodesPair(NULL, dst_root)); |
+ } |
+ |
+ void BeforeTraversingChild(ProfileNode* parent, ProfileNode* child) { |
+ if (IsTokenAcceptable(child->entry()->security_token_id(), |
+ parent->entry()->security_token_id())) { |
+ ProfileNode* clone = stack_.last().dst->FindOrAddChild(child->entry()); |
+ clone->IncreaseSelfTicks(child->self_ticks()); |
+ stack_.Add(NodesPair(child, clone)); |
+ } else { |
+ // Attribute ticks to parent node. |
+ stack_.last().dst->IncreaseSelfTicks(child->self_ticks()); |
+ } |
+ } |
+ |
+ void AfterAllChildrenTraversed(ProfileNode* parent) { } |
+ |
+ void AfterChildTraversed(ProfileNode*, ProfileNode* child) { |
+ if (stack_.last().src == child) { |
+ stack_.RemoveLast(); |
+ } |
+ } |
+ |
+ private: |
+ bool IsTokenAcceptable(int token, int parent_token) { |
+ if (token == CodeEntry::kNoSecurityToken |
+ || token == security_token_id_) return true; |
+ if (token == CodeEntry::kInheritsSecurityToken) { |
+ ASSERT(parent_token != CodeEntry::kInheritsSecurityToken); |
+ return parent_token == CodeEntry::kNoSecurityToken |
+ || parent_token == security_token_id_; |
+ } |
+ return false; |
+ } |
+ |
+ List<NodesPair> stack_; |
+ int security_token_id_; |
+}; |
+ |
+} // namespace |
+ |
+void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) { |
+ ms_to_ticks_scale_ = src->ms_to_ticks_scale_; |
+ FilteredCloneCallback cb(root_, security_token_id); |
+ src->TraverseDepthFirst(&cb); |
+ CalculateTotalTicks(); |
+} |
+ |
+ |
void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { |
ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0; |
} |
@@ -170,12 +301,13 @@ class Position { |
// Non-recursive implementation of a depth-first post-order tree traversal. |
template <typename Callback> |
-void ProfileTree::TraverseDepthFirstPostOrder(Callback* callback) { |
+void ProfileTree::TraverseDepthFirst(Callback* callback) { |
List<Position> stack(10); |
stack.Add(Position(root_)); |
- do { |
+ while (stack.length() > 0) { |
Position& current = stack.last(); |
if (current.has_current_child()) { |
+ callback->BeforeTraversingChild(current.node, current.current_child()); |
stack.Add(Position(current.current_child())); |
} else { |
callback->AfterAllChildrenTraversed(current.node); |
@@ -183,11 +315,11 @@ void ProfileTree::TraverseDepthFirstPostOrder(Callback* callback) { |
Position& parent = stack[stack.length() - 2]; |
callback->AfterChildTraversed(parent.node, current.node); |
parent.next_child(); |
- // Remove child from the stack. |
- stack.RemoveLast(); |
} |
+ // Remove child from the stack. |
+ stack.RemoveLast(); |
} |
- } while (stack.length() > 1 || stack.last().has_current_child()); |
+ } |
} |
@@ -195,6 +327,8 @@ namespace { |
class CalculateTotalTicksCallback { |
public: |
+ void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
+ |
void AfterAllChildrenTraversed(ProfileNode* node) { |
node->IncreaseTotalTicks(node->self_ticks()); |
} |
@@ -209,7 +343,7 @@ class CalculateTotalTicksCallback { |
void ProfileTree::CalculateTotalTicks() { |
CalculateTotalTicksCallback cb; |
- TraverseDepthFirstPostOrder(&cb); |
+ TraverseDepthFirst(&cb); |
} |
@@ -238,6 +372,15 @@ void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) { |
} |
+CpuProfile* CpuProfile::FilteredClone(int security_token_id) { |
+ ASSERT(security_token_id != CodeEntry::kNoSecurityToken); |
+ CpuProfile* clone = new CpuProfile(title_, uid_); |
+ clone->top_down_.FilteredClone(&top_down_, security_token_id); |
+ clone->bottom_up_.FilteredClone(&bottom_up_, security_token_id); |
+ return clone; |
+} |
+ |
+ |
void CpuProfile::ShortPrint() { |
OS::Print("top down "); |
top_down_.ShortPrint(); |
@@ -259,12 +402,13 @@ const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = |
CodeMap::CodeEntryInfo(NULL, 0); |
-void CodeMap::AddAlias(Address alias, Address addr) { |
+void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) { |
CodeTree::Locator locator; |
- if (tree_.Find(addr, &locator)) { |
- const CodeEntryInfo& entry_info = locator.value(); |
- tree_.Insert(alias, &locator); |
- locator.set_value(entry_info); |
+ 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)); |
} |
} |
@@ -295,8 +439,10 @@ void CodeMap::Print() { |
CpuProfilesCollection::CpuProfilesCollection() |
: function_and_resource_names_(StringsMatch), |
- profiles_uids_(CpuProfilesMatch), |
+ profiles_uids_(UidsMatch), |
current_profiles_semaphore_(OS::CreateSemaphore(1)) { |
+ // Create list of unabridged profiles. |
+ profiles_by_token_.Add(new List<CpuProfile*>()); |
} |
@@ -313,11 +459,15 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) { |
delete *profile_ptr; |
} |
+static void DeleteProfilesList(List<CpuProfile*>** list_ptr) { |
+ (*list_ptr)->Iterate(DeleteCpuProfile); |
+ delete *list_ptr; |
+} |
CpuProfilesCollection::~CpuProfilesCollection() { |
delete current_profiles_semaphore_; |
current_profiles_.Iterate(DeleteCpuProfile); |
- profiles_.Iterate(DeleteCpuProfile); |
+ profiles_by_token_.Iterate(DeleteProfilesList); |
code_entries_.Iterate(DeleteCodeEntry); |
args_count_names_.Iterate(DeleteArgsCountName); |
for (HashMap::Entry* p = function_and_resource_names_.Start(); |
@@ -349,7 +499,8 @@ bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) { |
} |
-CpuProfile* CpuProfilesCollection::StopProfiling(const char* title, |
+CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id, |
+ const char* title, |
double actual_sampling_rate) { |
const int title_len = StrLength(title); |
CpuProfile* profile = NULL; |
@@ -365,29 +516,89 @@ CpuProfile* CpuProfilesCollection::StopProfiling(const char* title, |
if (profile != NULL) { |
profile->CalculateTotalTicks(); |
profile->SetActualSamplingRate(actual_sampling_rate); |
- profiles_.Add(profile); |
+ List<CpuProfile*>* unabridged_list = |
+ profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
+ unabridged_list->Add(profile); |
HashMap::Entry* entry = |
profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()), |
static_cast<uint32_t>(profile->uid()), |
true); |
ASSERT(entry->value == NULL); |
- entry->value = profile; |
+ entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1); |
+ return GetProfile(security_token_id, profile->uid()); |
} |
- return profile; |
+ return NULL; |
} |
-CpuProfile* CpuProfilesCollection::StopProfiling(String* title, |
+CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id, |
+ String* title, |
double actual_sampling_rate) { |
- return StopProfiling(GetName(title), actual_sampling_rate); |
+ return StopProfiling(security_token_id, GetName(title), actual_sampling_rate); |
} |
-CpuProfile* CpuProfilesCollection::GetProfile(unsigned uid) { |
+CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id, |
+ unsigned uid) { |
HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid), |
static_cast<uint32_t>(uid), |
false); |
- return entry != NULL ? reinterpret_cast<CpuProfile*>(entry->value) : NULL; |
+ int index; |
+ if (entry != NULL) { |
+ index = reinterpret_cast<int>(entry->value); |
+ } else { |
+ return NULL; |
+ } |
+ List<CpuProfile*>* unabridged_list = |
+ profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
+ if (security_token_id == CodeEntry::kNoSecurityToken) { |
+ return unabridged_list->at(index); |
+ } |
+ List<CpuProfile*>* list = GetProfilesList(security_token_id); |
+ if (list->at(index) == NULL) { |
+ list->at(index) = |
+ unabridged_list->at(index)->FilteredClone(security_token_id); |
+ } |
+ return list->at(index); |
+} |
+ |
+ |
+int CpuProfilesCollection::TokenToIndex(int security_token_id) { |
+ ASSERT(CodeEntry::kNoSecurityToken == -1); |
+ return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ... |
+} |
+ |
+ |
+List<CpuProfile*>* CpuProfilesCollection::GetProfilesList( |
+ int security_token_id) { |
+ const int index = TokenToIndex(security_token_id); |
+ profiles_by_token_.AddBlock(NULL, profiles_by_token_.length() - index + 1); |
+ List<CpuProfile*>* unabridged_list = |
+ profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
+ const int current_count = unabridged_list->length(); |
+ if (profiles_by_token_[index] == NULL) { |
+ profiles_by_token_[index] = new List<CpuProfile*>(current_count); |
+ } |
+ List<CpuProfile*>* list = profiles_by_token_[index]; |
+ list->AddBlock(NULL, current_count - list->length()); |
+ return list; |
+} |
+ |
+ |
+List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) { |
+ List<CpuProfile*>* unabridged_list = |
+ profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)]; |
+ if (security_token_id == CodeEntry::kNoSecurityToken) { |
+ return unabridged_list; |
+ } |
+ List<CpuProfile*>* list = GetProfilesList(security_token_id); |
+ const int current_count = unabridged_list->length(); |
+ for (int i = 0; i < current_count; ++i) { |
+ if (list->at(i) == NULL) { |
+ list->at(i) = unabridged_list->at(i)->FilteredClone(security_token_id); |
+ } |
+ } |
+ return list; |
} |
@@ -399,7 +610,8 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
CodeEntry::kEmptyNamePrefix, |
GetFunctionName(name), |
GetName(resource_name), |
- line_number); |
+ line_number, |
+ CodeEntry::kNoSecurityToken); |
code_entries_.Add(entry); |
return entry; |
} |
@@ -411,7 +623,8 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
CodeEntry::kEmptyNamePrefix, |
GetFunctionName(name), |
"", |
- v8::CpuProfileNode::kNoLineNumberInfo); |
+ v8::CpuProfileNode::kNoLineNumberInfo, |
+ CodeEntry::kNoSecurityToken); |
code_entries_.Add(entry); |
return entry; |
} |
@@ -424,7 +637,8 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
name_prefix, |
GetName(name), |
"", |
- v8::CpuProfileNode::kNoLineNumberInfo); |
+ v8::CpuProfileNode::kNoLineNumberInfo, |
+ CodeEntry::kInheritsSecurityToken); |
code_entries_.Add(entry); |
return entry; |
} |
@@ -436,7 +650,15 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag, |
"args_count: ", |
GetName(args_count), |
"", |
- v8::CpuProfileNode::kNoLineNumberInfo); |
+ v8::CpuProfileNode::kNoLineNumberInfo, |
+ CodeEntry::kInheritsSecurityToken); |
+ code_entries_.Add(entry); |
+ return entry; |
+} |
+ |
+ |
+CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) { |
+ CodeEntry* entry = new CodeEntry(security_token_id); |
code_entries_.Add(entry); |
return entry; |
} |
@@ -547,8 +769,13 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
*entry = NULL; |
} else { |
CodeEntry* pc_entry = *entries.start(); |
- if (pc_entry == NULL || pc_entry->is_js_function()) |
+ 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++; |
} |