From 12d252eb810f7ae3409faee2ecb1be270f294164 Mon Sep 17 00:00:00 2001 From: "mikhail.naganov@gmail.com" Date: Mon, 15 Mar 2010 14:11:19 +0000 Subject: [PATCH] Start migrating profiles processing to C++. Adding code for maintaining (address -> name) mapping and building call trees. Review URL: http://codereview.chromium.org/910002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4131 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/SConscript | 1 + src/profile-generator-inl.h | 88 ++++++ src/profile-generator.cc | 295 ++++++++++++++++++++ src/profile-generator.h | 233 ++++++++++++++++ src/splay-tree-inl.h | 74 +++-- src/splay-tree.h | 12 + test/cctest/SConscript | 1 + test/cctest/test-profile-generator.cc | 362 +++++++++++++++++++++++++ tools/gyp/v8.gyp | 3 + tools/v8.xcodeproj/project.pbxproj | 10 + tools/visual_studio/v8_base.vcproj | 12 + tools/visual_studio/v8_base_arm.vcproj | 12 + tools/visual_studio/v8_base_x64.vcproj | 12 + 13 files changed, 1095 insertions(+), 20 deletions(-) create mode 100644 src/profile-generator-inl.h create mode 100644 src/profile-generator.cc create mode 100644 src/profile-generator.h create mode 100644 test/cctest/test-profile-generator.cc diff --git a/src/SConscript b/src/SConscript index 44b6b5b4f..ce41cb0fa 100755 --- a/src/SConscript +++ b/src/SConscript @@ -80,6 +80,7 @@ SOURCES = { objects.cc oprofile-agent.cc parser.cc + profile-generator.cc property.cc regexp-macro-assembler-irregexp.cc regexp-macro-assembler.cc diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h new file mode 100644 index 000000000..090ad8f30 --- /dev/null +++ b/src/profile-generator-inl.h @@ -0,0 +1,88 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_PROFILE_GENERATOR_INL_H_ +#define V8_PROFILE_GENERATOR_INL_H_ + +#include "profile-generator.h" + +namespace v8 { +namespace internal { + + +bool CodeEntry::is_js_function() { + return tag_ == Logger::FUNCTION_TAG + || tag_ == Logger::LAZY_COMPILE_TAG + || tag_ == Logger::SCRIPT_TAG; +} + + +StaticNameCodeEntry::StaticNameCodeEntry(Logger::LogEventsAndTags tag, + const char* name) + : CodeEntry(tag), + name_(name) { +} + + +ManagedNameCodeEntry::ManagedNameCodeEntry(Logger::LogEventsAndTags tag, + String* name, + const char* resource_name, + int line_number) + : CodeEntry(tag), + name_(name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach()), + resource_name_(resource_name), + line_number_(line_number) { +} + + +ProfileNode::ProfileNode(CodeEntry* entry) + : entry_(entry), + total_ticks_(0), + self_ticks_(0), + children_(CodeEntriesMatch) { +} + + +void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { + CodeTree::Locator locator; + tree_.Insert(addr, &locator); + locator.set_value(CodeEntryInfo(entry, size)); +} + + +void CodeMap::MoveCode(Address from, Address to) { + tree_.Move(from, to); +} + +void CodeMap::DeleteCode(Address addr) { + tree_.Remove(addr); +} + + +} } // namespace v8::internal + +#endif // V8_PROFILE_GENERATOR_INL_H_ diff --git a/src/profile-generator.cc b/src/profile-generator.cc new file mode 100644 index 000000000..5c64d362c --- /dev/null +++ b/src/profile-generator.cc @@ -0,0 +1,295 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "v8.h" + +#include "profile-generator-inl.h" + + +namespace v8 { +namespace internal { + + +ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { + HashMap::Entry* map_entry = + children_.Lookup(entry, CodeEntryHash(entry), false); + return map_entry != NULL ? + reinterpret_cast(map_entry->value) : NULL; +} + + +ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { + HashMap::Entry* map_entry = + children_.Lookup(entry, CodeEntryHash(entry), true); + if (map_entry->value == NULL) { + // New node added. + map_entry->value = new ProfileNode(entry); + } + return reinterpret_cast(map_entry->value); +} + + +void ProfileNode::Print(int indent) { + OS::Print("%4u %4u %*c %s\n", + total_ticks_, self_ticks_, + indent, ' ', + entry_ != NULL ? entry_->name() : ""); + for (HashMap::Entry* p = children_.Start(); + p != NULL; + p = children_.Next(p)) { + reinterpret_cast(p->value)->Print(indent + 2); + } +} + + +namespace { + +class DeleteNodesCallback { + public: + void AfterAllChildrenTraversed(ProfileNode* node) { + delete node; + } + + void AfterChildTraversed(ProfileNode*, ProfileNode*) { } +}; + +} // namespace + + +ProfileTree::~ProfileTree() { + DeleteNodesCallback cb; + TraverseBreadthFirstPostOrder(&cb); +} + + +void ProfileTree::AddPathFromEnd(const Vector& path) { + ProfileNode* node = root_; + for (CodeEntry** entry = path.start() + path.length() - 1; + entry != path.start() - 1; + --entry) { + if (*entry != NULL) { + node = node->FindOrAddChild(*entry); + } + } + node->IncrementSelfTicks(); +} + + +void ProfileTree::AddPathFromStart(const Vector& path) { + ProfileNode* node = root_; + for (CodeEntry** entry = path.start(); + entry != path.start() + path.length(); + ++entry) { + if (*entry != NULL) { + node = node->FindOrAddChild(*entry); + } + } + node->IncrementSelfTicks(); +} + + +namespace { + +struct Position { + Position(ProfileNode* a_node, HashMap::Entry* a_p) + : node(a_node), p(a_p) { } + INLINE(ProfileNode* current_child()) { + return reinterpret_cast(p->value); + } + ProfileNode* node; + HashMap::Entry* p; +}; + +} // namespace + + +template +void ProfileTree::TraverseBreadthFirstPostOrder(Callback* callback) { + List stack(10); + stack.Add(Position(root_, root_->children_.Start())); + do { + Position& current = stack.last(); + if (current.p != NULL) { + stack.Add(Position(current.current_child(), + current.current_child()->children_.Start())); + } else { + callback->AfterAllChildrenTraversed(current.node); + if (stack.length() > 1) { + Position& parent = stack[stack.length() - 2]; + callback->AfterChildTraversed(parent.node, current.node); + parent.p = parent.node->children_.Next(parent.p); + // Remove child from the stack. + stack.RemoveLast(); + } + } + } while (stack.length() > 1 || stack.last().p != NULL); +} + + +namespace { + +class CalculateTotalTicksCallback { + public: + void AfterAllChildrenTraversed(ProfileNode* node) { + node->IncreaseTotalTicks(node->self_ticks()); + } + + void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { + parent->IncreaseTotalTicks(child->total_ticks()); + } +}; + +} // namespace + + +// Non-recursive implementation of breadth-first tree traversal. +void ProfileTree::CalculateTotalTicks() { + CalculateTotalTicksCallback cb; + TraverseBreadthFirstPostOrder(&cb); +} + + +void ProfileTree::ShortPrint() { + OS::Print("root: %u %u\n", root_->total_ticks(), root_->self_ticks()); +} + + +void CpuProfile::AddPath(const Vector& path) { + top_down_.AddPathFromEnd(path); + bottom_up_.AddPathFromStart(path); +} + + +void CpuProfile::CalculateTotalTicks() { + top_down_.CalculateTotalTicks(); + bottom_up_.CalculateTotalTicks(); +} + + +void CpuProfile::ShortPrint() { + OS::Print("top down "); + top_down_.ShortPrint(); + OS::Print("bottom up "); + bottom_up_.ShortPrint(); +} + + +void CpuProfile::Print() { + OS::Print("[Top down]:\n"); + top_down_.Print(); + OS::Print("[Bottom up]:\n"); + bottom_up_.Print(); +} + + +const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; +const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = + CodeMap::CodeEntryInfo(NULL, 0); + + +void CodeMap::AddAlias(Address alias, Address addr) { + CodeTree::Locator locator; + if (tree_.Find(addr, &locator)) { + const CodeEntryInfo& entry_info = locator.value(); + tree_.Insert(alias, &locator); + locator.set_value(entry_info); + } +} + + +CodeEntry* CodeMap::FindEntry(Address addr) { + CodeTree::Locator locator; + if (tree_.FindGreatestLessThan(addr, &locator)) { + // locator.key() <= addr. Need to check that addr is within entry. + const CodeEntryInfo& entry = locator.value(); + if (addr < (locator.key() + entry.size)) + return entry.entry; + } + return NULL; +} + + +ProfileGenerator::ProfileGenerator() + : resource_names_(StringsMatch) { +} + + +static void CodeEntriesDeleter(CodeEntry** entry_ptr) { + delete *entry_ptr; +} + + +ProfileGenerator::~ProfileGenerator() { + for (HashMap::Entry* p = resource_names_.Start(); + p != NULL; + p = resource_names_.Next(p)) { + DeleteArray(reinterpret_cast(p->value)); + } + + code_entries_.Iterate(CodeEntriesDeleter); +} + + +CodeEntry* ProfileGenerator::NewCodeEntry( + Logger::LogEventsAndTags tag, + String* name, + String* resource_name, int line_number) { + const char* cached_resource_name = NULL; + if (resource_name->IsString()) { + // As we copy contents of resource names, and usually they are repeated, + // we cache names by string hashcode. + HashMap::Entry* cache_entry = + resource_names_.Lookup(resource_name, + StringEntryHash(resource_name), + true); + if (cache_entry->value == NULL) { + // New entry added. + cache_entry->value = + resource_name->ToCString(DISALLOW_NULLS, + ROBUST_STRING_TRAVERSAL).Detach(); + } + cached_resource_name = reinterpret_cast(cache_entry->value); + } + + CodeEntry* entry = new ManagedNameCodeEntry(tag, + name, + cached_resource_name, + line_number); + code_entries_.Add(entry); + return entry; +} + + +CodeEntry* ProfileGenerator::NewCodeEntry( + Logger::LogEventsAndTags tag, + const char* name) { + CodeEntry* entry = new StaticNameCodeEntry(tag, name); + code_entries_.Add(entry); + return entry; +} + +} } // namespace v8::internal diff --git a/src/profile-generator.h b/src/profile-generator.h new file mode 100644 index 000000000..c3843bf91 --- /dev/null +++ b/src/profile-generator.h @@ -0,0 +1,233 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_PROFILE_GENERATOR_H_ +#define V8_PROFILE_GENERATOR_H_ + +#include "hashmap.h" + +namespace v8 { +namespace internal { + + +class CodeEntry { + public: + virtual ~CodeEntry() { } + + virtual const char* name() = 0; + INLINE(bool is_js_function()); + + protected: + INLINE(explicit CodeEntry(Logger::LogEventsAndTags tag)) + : tag_(tag) { } + + private: + Logger::LogEventsAndTags tag_; + + DISALLOW_COPY_AND_ASSIGN(CodeEntry); +}; + + +class StaticNameCodeEntry : public CodeEntry { + public: + INLINE(StaticNameCodeEntry(Logger::LogEventsAndTags tag, + const char* name)); + + INLINE(virtual const char* name()) { return name_ != NULL ? name_ : ""; } + + private: + const char* name_; + + DISALLOW_COPY_AND_ASSIGN(StaticNameCodeEntry); +}; + + +class ManagedNameCodeEntry : public CodeEntry { + public: + INLINE(ManagedNameCodeEntry(Logger::LogEventsAndTags tag, + String* name, + const char* resource_name, int line_number)); + + INLINE(virtual const char* name()) { return !name_.is_empty() ? *name_ : ""; } + + private: + SmartPointer name_; + const char* resource_name_; + int line_number_; + + DISALLOW_COPY_AND_ASSIGN(ManagedNameCodeEntry); +}; + + +class ProfileNode { + public: + INLINE(explicit ProfileNode(CodeEntry* entry)); + + ProfileNode* FindChild(CodeEntry* entry); + ProfileNode* FindOrAddChild(CodeEntry* entry); + INLINE(void IncrementSelfTicks()) { ++self_ticks_; } + INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; } + + INLINE(unsigned total_ticks()) { return total_ticks_; } + INLINE(unsigned self_ticks()) { return self_ticks_; } + + void Print(int indent); + + private: + INLINE(static bool CodeEntriesMatch(void* key1, void* key2)) { + return key1 == key2; + } + + INLINE(static bool CodeEntryHash(CodeEntry* entry)) { + return static_cast(reinterpret_cast(entry)); + } + + CodeEntry* entry_; + unsigned total_ticks_; + unsigned self_ticks_; + // CodeEntry* -> ProfileNode* + HashMap children_; + + friend class ProfileTree; + + DISALLOW_COPY_AND_ASSIGN(ProfileNode); +}; + + +class ProfileTree BASE_EMBEDDED { + public: + ProfileTree() : root_(new ProfileNode(NULL)) { } + ~ProfileTree(); + + void AddPathFromEnd(const Vector& path); + void AddPathFromStart(const Vector& path); + void CalculateTotalTicks(); + + ProfileNode* root() { return root_; } + + void ShortPrint(); + void Print() { + root_->Print(0); + } + + private: + template + void TraverseBreadthFirstPostOrder(Callback* callback); + + ProfileNode* root_; + + DISALLOW_COPY_AND_ASSIGN(ProfileTree); +}; + + +class CpuProfile BASE_EMBEDDED { + public: + CpuProfile() { } + // Add pc -> ... -> main() call path to the profile. + void AddPath(const Vector& path); + void CalculateTotalTicks(); + + void ShortPrint(); + void Print(); + + private: + ProfileTree top_down_; + ProfileTree bottom_up_; + + DISALLOW_COPY_AND_ASSIGN(CpuProfile); +}; + + +class CodeMap BASE_EMBEDDED { + public: + CodeMap() { } + INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size)); + INLINE(void MoveCode(Address from, Address to)); + INLINE(void DeleteCode(Address addr)); + void AddAlias(Address alias, Address addr); + CodeEntry* FindEntry(Address addr); + + private: + struct CodeEntryInfo { + CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) + : entry(an_entry), size(a_size) { } + CodeEntry* entry; + unsigned size; + }; + + struct CodeTreeConfig { + typedef Address Key; + typedef CodeEntryInfo Value; + static const Key kNoKey; + static const Value kNoValue; + static int Compare(const Key& a, const Key& b) { + return a < b ? -1 : (a > b ? 1 : 0); + } + }; + typedef SplayTree CodeTree; + + CodeTree tree_; + + DISALLOW_COPY_AND_ASSIGN(CodeMap); +}; + + +class ProfileGenerator { + public: + ProfileGenerator(); + ~ProfileGenerator(); + + CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, + String* name, String* resource_name, int line_number); + CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name); + + INLINE(CpuProfile* profile()) { return &profile_; } + INLINE(CodeMap* code_map()) { return &code_map_; } + + private: + INLINE(static bool StringsMatch(void* key1, void* key2)) { + return key1 == key2; + } + + INLINE(static bool StringEntryHash(String* entry)) { + return entry->Hash(); + } + + CpuProfile profile_; + CodeMap code_map_; + typedef List CodeEntryList; + CodeEntryList code_entries_; + // String::Hash -> const char* + HashMap resource_names_; + + DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); +}; + + +} } // namespace v8::internal + +#endif // V8_PROFILE_GENERATOR_H_ diff --git a/src/splay-tree-inl.h b/src/splay-tree-inl.h index 16fe25e97..9c2287eab 100644 --- a/src/splay-tree-inl.h +++ b/src/splay-tree-inl.h @@ -58,16 +58,7 @@ bool SplayTree::Insert(const Key& key, Locator* locator) { } // Insert the new node. Node* node = new Node(key, Config::kNoValue); - if (cmp > 0) { - node->left_ = root_; - node->right_ = root_->right_; - root_->right_ = NULL; - } else { - node->right_ = root_; - node->left_ = root_->left_; - root_->left_ = NULL; - } - root_ = node; + InsertInternal(cmp, node); } locator->bind(root_); return true; @@ -75,11 +66,32 @@ bool SplayTree::Insert(const Key& key, Locator* locator) { template -bool SplayTree::Find(const Key& key, Locator* locator) { +void SplayTree::InsertInternal(int cmp, Node* node) { + if (cmp > 0) { + node->left_ = root_; + node->right_ = root_->right_; + root_->right_ = NULL; + } else { + node->right_ = root_; + node->left_ = root_->left_; + root_->left_ = NULL; + } + root_ = node; +} + + +template +bool SplayTree::FindInternal(const Key& key) { if (is_empty()) return false; Splay(key); - if (Config::Compare(key, root_->key_) == 0) { + return Config::Compare(key, root_->key_) == 0; +} + + +template +bool SplayTree::Find(const Key& key, Locator* locator) { + if (FindInternal(key)) { locator->bind(root_); return true; } else { @@ -161,15 +173,38 @@ bool SplayTree::FindLeast(Locator* locator) { template -bool SplayTree::Remove(const Key& key) { - // Bail if the tree is empty - if (is_empty()) +bool SplayTree::Move(const Key& old_key, + const Key& new_key) { + if (!FindInternal(old_key)) return false; - // Splay on the key to move the node with the given key to the top. - Splay(key); - // Bail if the key is not in the tree - if (Config::Compare(key, root_->key_) != 0) + Node* node_to_move = root_; + RemoveRootNode(old_key); + Splay(new_key); + int cmp = Config::Compare(new_key, root_->key_); + if (cmp == 0) { + // A node with the target key already exists. + delete node_to_move; return false; + } + node_to_move->key_ = new_key; + InsertInternal(cmp, node_to_move); + return true; +} + + +template +bool SplayTree::Remove(const Key& key) { + if (!FindInternal(key)) + return false; + Node* node_to_remove = root_; + RemoveRootNode(key); + delete node_to_remove; + return true; +} + + +template +void SplayTree::RemoveRootNode(const Key& key) { if (root_->left_ == NULL) { // No left child, so the new tree is just the right child. root_ = root_->right_; @@ -184,7 +219,6 @@ bool SplayTree::Remove(const Key& key) { // root. root_->right_ = right; } - return true; } diff --git a/src/splay-tree.h b/src/splay-tree.h index b0f415d82..c26527600 100644 --- a/src/splay-tree.h +++ b/src/splay-tree.h @@ -88,6 +88,9 @@ class SplayTree { // Find the mapping with the least key in this tree. bool FindLeast(Locator* locator); + // Move the node from one key to another. + bool Move(const Key& old_key, const Key& new_key); + // Remove the node with the given key from the tree. bool Remove(const Key& key); @@ -151,6 +154,15 @@ class SplayTree { void ResetRoot() { root_ = NULL; } private: + // Search for a node with a given key. If found, root_ points + // to the node. + bool FindInternal(const Key& key); + + // Inserts a node assuming that root_ is already set up. + void InsertInternal(int cmp, Node* node); + + // Removes root_ node. + void RemoveRootNode(const Key& key); template class NodeToPairAdaptor BASE_EMBEDDED { diff --git a/test/cctest/SConscript b/test/cctest/SConscript index e35d45474..f4964ae6a 100644 --- a/test/cctest/SConscript +++ b/test/cctest/SConscript @@ -58,6 +58,7 @@ SOURCES = { 'test-log-utils.cc', 'test-mark-compact.cc', 'test-parsing.cc', + 'test-profile-generator.cc', 'test-regexp.cc', 'test-serialize.cc', 'test-sockets.cc', diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc new file mode 100644 index 000000000..2d673d456 --- /dev/null +++ b/test/cctest/test-profile-generator.cc @@ -0,0 +1,362 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// +// Tests of profiles generator and utilities. + +#include "v8.h" +#include "profile-generator-inl.h" +#include "cctest.h" + +namespace i = v8::internal; + +using i::CodeEntry; +using i::CodeMap; +using i::ProfileNode; +using i::ProfileTree; +using i::StaticNameCodeEntry; +using i::Vector; + + +TEST(ProfileNodeFindOrAddChild) { + ProfileNode node(NULL); + StaticNameCodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa"); + ProfileNode* childNode1 = node.FindOrAddChild(&entry1); + CHECK_NE(NULL, childNode1); + CHECK_EQ(childNode1, node.FindOrAddChild(&entry1)); + StaticNameCodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb"); + ProfileNode* childNode2 = node.FindOrAddChild(&entry2); + CHECK_NE(NULL, childNode2); + CHECK_NE(childNode1, childNode2); + CHECK_EQ(childNode1, node.FindOrAddChild(&entry1)); + CHECK_EQ(childNode2, node.FindOrAddChild(&entry2)); + StaticNameCodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc"); + ProfileNode* childNode3 = node.FindOrAddChild(&entry3); + CHECK_NE(NULL, childNode3); + CHECK_NE(childNode1, childNode3); + CHECK_NE(childNode2, childNode3); + CHECK_EQ(childNode1, node.FindOrAddChild(&entry1)); + CHECK_EQ(childNode2, node.FindOrAddChild(&entry2)); + CHECK_EQ(childNode3, node.FindOrAddChild(&entry3)); +} + + +namespace { + +class ProfileTreeTestHelper { + public: + explicit ProfileTreeTestHelper(ProfileTree* tree) + : tree_(tree) { } + + ProfileNode* Walk(CodeEntry* entry1, + CodeEntry* entry2 = NULL, + CodeEntry* entry3 = NULL) { + ProfileNode* node = tree_->root(); + node = node->FindChild(entry1); + if (node == NULL) return NULL; + if (entry2 != NULL) { + node = node->FindChild(entry2); + if (node == NULL) return NULL; + } + if (entry3 != NULL) { + node = node->FindChild(entry3); + } + return node; + } + + private: + ProfileTree* tree_; +}; + +} // namespace + +TEST(ProfileTreeAddPathFromStart) { + StaticNameCodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa"); + StaticNameCodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb"); + StaticNameCodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc"); + ProfileTree tree; + ProfileTreeTestHelper helper(&tree); + CHECK_EQ(NULL, helper.Walk(&entry1)); + CHECK_EQ(NULL, helper.Walk(&entry2)); + CHECK_EQ(NULL, helper.Walk(&entry3)); + + CodeEntry* path[] = {NULL, &entry1, NULL, &entry2, NULL, NULL, &entry3, NULL}; + Vector path_vec(path, sizeof(path) / sizeof(path[0])); + tree.AddPathFromStart(path_vec); + CHECK_EQ(NULL, helper.Walk(&entry2)); + CHECK_EQ(NULL, helper.Walk(&entry3)); + ProfileNode* node1 = helper.Walk(&entry1); + CHECK_NE(NULL, node1); + CHECK_EQ(0, node1->total_ticks()); + CHECK_EQ(0, node1->self_ticks()); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry3)); + ProfileNode* node2 = helper.Walk(&entry1, &entry2); + CHECK_NE(NULL, node2); + CHECK_NE(node1, node2); + CHECK_EQ(0, node2->total_ticks()); + CHECK_EQ(0, node2->self_ticks()); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2)); + ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3); + CHECK_NE(NULL, node3); + CHECK_NE(node1, node3); + CHECK_NE(node2, node3); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(1, node3->self_ticks()); + + tree.AddPathFromStart(path_vec); + CHECK_EQ(node1, helper.Walk(&entry1)); + CHECK_EQ(node2, helper.Walk(&entry1, &entry2)); + CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3)); + CHECK_EQ(0, node1->total_ticks()); + CHECK_EQ(0, node1->self_ticks()); + CHECK_EQ(0, node2->total_ticks()); + CHECK_EQ(0, node2->self_ticks()); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(2, node3->self_ticks()); + + CodeEntry* path2[] = {&entry1, &entry2, &entry2}; + Vector path2_vec(path2, sizeof(path2) / sizeof(path2[0])); + tree.AddPathFromStart(path2_vec); + CHECK_EQ(NULL, helper.Walk(&entry2)); + CHECK_EQ(NULL, helper.Walk(&entry3)); + CHECK_EQ(node1, helper.Walk(&entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry3)); + CHECK_EQ(node2, helper.Walk(&entry1, &entry2)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1)); + CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3)); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(2, node3->self_ticks()); + ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2); + CHECK_NE(NULL, node4); + CHECK_NE(node3, node4); + CHECK_EQ(0, node4->total_ticks()); + CHECK_EQ(1, node4->self_ticks()); +} + + +TEST(ProfileTreeAddPathFromEnd) { + StaticNameCodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa"); + StaticNameCodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb"); + StaticNameCodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc"); + ProfileTree tree; + ProfileTreeTestHelper helper(&tree); + CHECK_EQ(NULL, helper.Walk(&entry1)); + CHECK_EQ(NULL, helper.Walk(&entry2)); + CHECK_EQ(NULL, helper.Walk(&entry3)); + + CodeEntry* path[] = {NULL, &entry3, NULL, &entry2, NULL, NULL, &entry1, NULL}; + Vector path_vec(path, sizeof(path) / sizeof(path[0])); + tree.AddPathFromEnd(path_vec); + CHECK_EQ(NULL, helper.Walk(&entry2)); + CHECK_EQ(NULL, helper.Walk(&entry3)); + ProfileNode* node1 = helper.Walk(&entry1); + CHECK_NE(NULL, node1); + CHECK_EQ(0, node1->total_ticks()); + CHECK_EQ(0, node1->self_ticks()); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry3)); + ProfileNode* node2 = helper.Walk(&entry1, &entry2); + CHECK_NE(NULL, node2); + CHECK_NE(node1, node2); + CHECK_EQ(0, node2->total_ticks()); + CHECK_EQ(0, node2->self_ticks()); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry2)); + ProfileNode* node3 = helper.Walk(&entry1, &entry2, &entry3); + CHECK_NE(NULL, node3); + CHECK_NE(node1, node3); + CHECK_NE(node2, node3); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(1, node3->self_ticks()); + + tree.AddPathFromEnd(path_vec); + CHECK_EQ(node1, helper.Walk(&entry1)); + CHECK_EQ(node2, helper.Walk(&entry1, &entry2)); + CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3)); + CHECK_EQ(0, node1->total_ticks()); + CHECK_EQ(0, node1->self_ticks()); + CHECK_EQ(0, node2->total_ticks()); + CHECK_EQ(0, node2->self_ticks()); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(2, node3->self_ticks()); + + CodeEntry* path2[] = {&entry2, &entry2, &entry1}; + Vector path2_vec(path2, sizeof(path2) / sizeof(path2[0])); + tree.AddPathFromEnd(path2_vec); + CHECK_EQ(NULL, helper.Walk(&entry2)); + CHECK_EQ(NULL, helper.Walk(&entry3)); + CHECK_EQ(node1, helper.Walk(&entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry1)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry3)); + CHECK_EQ(node2, helper.Walk(&entry1, &entry2)); + CHECK_EQ(NULL, helper.Walk(&entry1, &entry2, &entry1)); + CHECK_EQ(node3, helper.Walk(&entry1, &entry2, &entry3)); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(2, node3->self_ticks()); + ProfileNode* node4 = helper.Walk(&entry1, &entry2, &entry2); + CHECK_NE(NULL, node4); + CHECK_NE(node3, node4); + CHECK_EQ(0, node4->total_ticks()); + CHECK_EQ(1, node4->self_ticks()); +} + + +TEST(ProfileTreeCalculateTotalTicks) { + ProfileTree empty_tree; + CHECK_EQ(0, empty_tree.root()->total_ticks()); + CHECK_EQ(0, empty_tree.root()->self_ticks()); + empty_tree.CalculateTotalTicks(); + CHECK_EQ(0, empty_tree.root()->total_ticks()); + CHECK_EQ(0, empty_tree.root()->self_ticks()); + empty_tree.root()->IncrementSelfTicks(); + CHECK_EQ(0, empty_tree.root()->total_ticks()); + CHECK_EQ(1, empty_tree.root()->self_ticks()); + empty_tree.CalculateTotalTicks(); + CHECK_EQ(1, empty_tree.root()->total_ticks()); + CHECK_EQ(1, empty_tree.root()->self_ticks()); + + StaticNameCodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa"); + StaticNameCodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb"); + CodeEntry* e1_path[] = {&entry1}; + Vector e1_path_vec( + e1_path, sizeof(e1_path) / sizeof(e1_path[0])); + CodeEntry* e1_e2_path[] = {&entry1, &entry2}; + Vector e1_e2_path_vec( + e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0])); + + ProfileTree flat_tree; + ProfileTreeTestHelper flat_helper(&flat_tree); + flat_tree.AddPathFromStart(e1_path_vec); + flat_tree.AddPathFromStart(e1_path_vec); + flat_tree.AddPathFromStart(e1_e2_path_vec); + flat_tree.AddPathFromStart(e1_e2_path_vec); + flat_tree.AddPathFromStart(e1_e2_path_vec); + // Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3} + CHECK_EQ(0, flat_tree.root()->total_ticks()); + CHECK_EQ(0, flat_tree.root()->self_ticks()); + ProfileNode* node1 = flat_helper.Walk(&entry1); + CHECK_NE(NULL, node1); + CHECK_EQ(0, node1->total_ticks()); + CHECK_EQ(2, node1->self_ticks()); + ProfileNode* node2 = flat_helper.Walk(&entry1, &entry2); + CHECK_NE(NULL, node2); + CHECK_EQ(0, node2->total_ticks()); + CHECK_EQ(3, node2->self_ticks()); + flat_tree.CalculateTotalTicks(); + // Must calculate {root,5,0} -> {entry1,5,2} -> {entry2,3,3} + CHECK_EQ(5, flat_tree.root()->total_ticks()); + CHECK_EQ(0, flat_tree.root()->self_ticks()); + CHECK_EQ(5, node1->total_ticks()); + CHECK_EQ(2, node1->self_ticks()); + CHECK_EQ(3, node2->total_ticks()); + CHECK_EQ(3, node2->self_ticks()); + + CodeEntry* e2_path[] = {&entry2}; + Vector e2_path_vec( + e2_path, sizeof(e2_path) / sizeof(e2_path[0])); + StaticNameCodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc"); + CodeEntry* e3_path[] = {&entry3}; + Vector e3_path_vec( + e3_path, sizeof(e3_path) / sizeof(e3_path[0])); + + ProfileTree wide_tree; + ProfileTreeTestHelper wide_helper(&wide_tree); + wide_tree.AddPathFromStart(e1_path_vec); + wide_tree.AddPathFromStart(e1_path_vec); + wide_tree.AddPathFromStart(e1_e2_path_vec); + wide_tree.AddPathFromStart(e2_path_vec); + wide_tree.AddPathFromStart(e2_path_vec); + wide_tree.AddPathFromStart(e2_path_vec); + wide_tree.AddPathFromStart(e3_path_vec); + wide_tree.AddPathFromStart(e3_path_vec); + wide_tree.AddPathFromStart(e3_path_vec); + wide_tree.AddPathFromStart(e3_path_vec); + // Results in -> {entry1,0,2} -> {entry2,0,1} + // {root,0,0} -> {entry2,0,3} + // -> {entry3,0,4} + CHECK_EQ(0, wide_tree.root()->total_ticks()); + CHECK_EQ(0, wide_tree.root()->self_ticks()); + node1 = wide_helper.Walk(&entry1); + CHECK_NE(NULL, node1); + CHECK_EQ(0, node1->total_ticks()); + CHECK_EQ(2, node1->self_ticks()); + ProfileNode* node1_2 = wide_helper.Walk(&entry1, &entry2); + CHECK_NE(NULL, node1_2); + CHECK_EQ(0, node1_2->total_ticks()); + CHECK_EQ(1, node1_2->self_ticks()); + node2 = wide_helper.Walk(&entry2); + CHECK_NE(NULL, node2); + CHECK_EQ(0, node2->total_ticks()); + CHECK_EQ(3, node2->self_ticks()); + ProfileNode* node3 = wide_helper.Walk(&entry3); + CHECK_NE(NULL, node3); + CHECK_EQ(0, node3->total_ticks()); + CHECK_EQ(4, node3->self_ticks()); + wide_tree.CalculateTotalTicks(); + // Calculates -> {entry1,3,2} -> {entry2,1,1} + // {root,10,0} -> {entry2,3,3} + // -> {entry3,4,4} + CHECK_EQ(10, wide_tree.root()->total_ticks()); + CHECK_EQ(0, wide_tree.root()->self_ticks()); + CHECK_EQ(3, node1->total_ticks()); + CHECK_EQ(2, node1->self_ticks()); + CHECK_EQ(1, node1_2->total_ticks()); + CHECK_EQ(1, node1_2->self_ticks()); + CHECK_EQ(3, node2->total_ticks()); + CHECK_EQ(3, node2->self_ticks()); + CHECK_EQ(4, node3->total_ticks()); + CHECK_EQ(4, node3->self_ticks()); +} + + +static inline i::Address ToAddress(int n) { + return reinterpret_cast(n); +} + +TEST(CodeMapAddCode) { + CodeMap code_map; + StaticNameCodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa"); + StaticNameCodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb"); + StaticNameCodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc"); + StaticNameCodeEntry entry4(i::Logger::FUNCTION_TAG, "ddd"); + code_map.AddCode(ToAddress(0x1500), &entry1, 0x200); + code_map.AddCode(ToAddress(0x1700), &entry2, 0x100); + code_map.AddCode(ToAddress(0x1900), &entry3, 0x50); + code_map.AddCode(ToAddress(0x1950), &entry4, 0x10); + CHECK_EQ(NULL, code_map.FindEntry(0)); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500 - 1))); + CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500))); + CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x100))); + CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500 + 0x200 - 1))); + CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700))); + CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x50))); + CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700 + 0x100 - 1))); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700 + 0x100))); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1900 - 1))); + CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900))); + CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1900 + 0x28))); + CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950))); + CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x7))); + CHECK_EQ(&entry4, code_map.FindEntry(ToAddress(0x1950 + 0x10 - 1))); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1950 + 0x10))); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0xFFFFFFFF))); +} + + +TEST(CodeMapMoveAndDeleteCode) { + CodeMap code_map; + StaticNameCodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa"); + StaticNameCodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb"); + code_map.AddCode(ToAddress(0x1500), &entry1, 0x200); + code_map.AddCode(ToAddress(0x1700), &entry2, 0x100); + CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500))); + CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700))); + code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800)); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500))); + CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700))); + CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800))); + code_map.DeleteCode(ToAddress(0x1700)); + CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700))); + CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800))); +} diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 4270b1427..d859fb0d7 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -340,6 +340,9 @@ '../../src/prettyprinter.h', '../../src/property.cc', '../../src/property.h', + '../../src/profile-generator-inl.h', + '../../src/profile-generator.cc', + '../../src/profile-generator.h', '../../src/regexp-macro-assembler-irregexp-inl.h', '../../src/regexp-macro-assembler-irregexp.cc', '../../src/regexp-macro-assembler-irregexp.h', diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj index 3ffd18299..ccb197a24 100644 --- a/tools/v8.xcodeproj/project.pbxproj +++ b/tools/v8.xcodeproj/project.pbxproj @@ -212,6 +212,8 @@ 9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */; }; 9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; }; 9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; }; + 9F73E3B1114E61A100F84A5A /* profile-generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F73E3AF114E61A100F84A5A /* profile-generator.cc */; }; + 9F73E3B2114E61A100F84A5A /* profile-generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F73E3AF114E61A100F84A5A /* profile-generator.cc */; }; 9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; }; 9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; }; 9FBE03DE10BD409900F8BFBA /* fast-codegen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */; }; @@ -552,6 +554,9 @@ 9F11D99F105AF0A300EBE5B2 /* heap-profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-profiler.h"; sourceTree = ""; }; 9F4B7B870FCC877A00DC4117 /* log-utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "log-utils.cc"; sourceTree = ""; }; 9F4B7B880FCC877A00DC4117 /* log-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "log-utils.h"; sourceTree = ""; }; + 9F73E3AE114E61A100F84A5A /* profile-generator-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "profile-generator-inl.h"; sourceTree = ""; }; + 9F73E3AF114E61A100F84A5A /* profile-generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "profile-generator.cc"; sourceTree = ""; }; + 9F73E3B0114E61A100F84A5A /* profile-generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "profile-generator.h"; sourceTree = ""; }; 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = ""; }; 9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "func-name-inferrer.h"; sourceTree = ""; }; 9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "fast-codegen.cc"; sourceTree = ""; }; @@ -804,6 +809,9 @@ 897FF16A0E719B8F00D62E90 /* platform.h */, 897FF16B0E719B8F00D62E90 /* prettyprinter.cc */, 897FF16C0E719B8F00D62E90 /* prettyprinter.h */, + 9F73E3AE114E61A100F84A5A /* profile-generator-inl.h */, + 9F73E3AF114E61A100F84A5A /* profile-generator.cc */, + 9F73E3B0114E61A100F84A5A /* profile-generator.h */, 897FF16D0E719B8F00D62E90 /* property.cc */, 897FF16E0E719B8F00D62E90 /* property.h */, 89A15C700EE466D000B48DEB /* regexp-macro-assembler-arm.cc */, @@ -1239,6 +1247,7 @@ 9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */, 9FBE03DE10BD409900F8BFBA /* fast-codegen.cc in Sources */, 9FBE03E210BD40EA00F8BFBA /* fast-codegen-ia32.cc in Sources */, + 9F73E3B2114E61A100F84A5A /* profile-generator.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1348,6 +1357,7 @@ 9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */, 9FBE03DF10BD409900F8BFBA /* fast-codegen.cc in Sources */, 9FBE03E510BD412600F8BFBA /* fast-codegen-arm.cc in Sources */, + 9F73E3B1114E61A100F84A5A /* profile-generator.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/tools/visual_studio/v8_base.vcproj b/tools/visual_studio/v8_base.vcproj index 1a7e14c3a..37ea01c0e 100644 --- a/tools/visual_studio/v8_base.vcproj +++ b/tools/visual_studio/v8_base.vcproj @@ -684,6 +684,18 @@ RelativePath="..\..\src\parser.h" > + + + + + + diff --git a/tools/visual_studio/v8_base_arm.vcproj b/tools/visual_studio/v8_base_arm.vcproj index 346c5eb19..de2d65a24 100644 --- a/tools/visual_studio/v8_base_arm.vcproj +++ b/tools/visual_studio/v8_base_arm.vcproj @@ -688,6 +688,18 @@ RelativePath="..\..\src\parser.h" > + + + + + + diff --git a/tools/visual_studio/v8_base_x64.vcproj b/tools/visual_studio/v8_base_x64.vcproj index 120dd190d..29f4ed77b 100644 --- a/tools/visual_studio/v8_base_x64.vcproj +++ b/tools/visual_studio/v8_base_x64.vcproj @@ -685,6 +685,18 @@ RelativePath="..\..\src\parser.h" > + + + + + + -- 2.34.1