Start migrating profiles processing to C++.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Mar 2010 14:11:19 +0000 (14:11 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Mar 2010 14:11:19 +0000 (14:11 +0000)
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

13 files changed:
src/SConscript
src/profile-generator-inl.h [new file with mode: 0644]
src/profile-generator.cc [new file with mode: 0644]
src/profile-generator.h [new file with mode: 0644]
src/splay-tree-inl.h
src/splay-tree.h
test/cctest/SConscript
test/cctest/test-profile-generator.cc [new file with mode: 0644]
tools/gyp/v8.gyp
tools/v8.xcodeproj/project.pbxproj
tools/visual_studio/v8_base.vcproj
tools/visual_studio/v8_base_arm.vcproj
tools/visual_studio/v8_base_x64.vcproj

index 44b6b5b..ce41cb0 100755 (executable)
@@ -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 (file)
index 0000000..090ad8f
--- /dev/null
@@ -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 (file)
index 0000000..5c64d36
--- /dev/null
@@ -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<ProfileNode*>(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<ProfileNode*>(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<ProfileNode*>(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<CodeEntry*>& 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<CodeEntry*>& 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<ProfileNode*>(p->value);
+  }
+  ProfileNode* node;
+  HashMap::Entry* p;
+};
+
+}  // namespace
+
+
+template <typename Callback>
+void ProfileTree::TraverseBreadthFirstPostOrder(Callback* callback) {
+  List<Position> 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<CodeEntry*>& 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<const char*>(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<const char*>(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 (file)
index 0000000..c3843bf
--- /dev/null
@@ -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<char> 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<int32_t>(reinterpret_cast<intptr_t>(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<CodeEntry*>& path);
+  void AddPathFromStart(const Vector<CodeEntry*>& path);
+  void CalculateTotalTicks();
+
+  ProfileNode* root() { return root_; }
+
+  void ShortPrint();
+  void Print() {
+    root_->Print(0);
+  }
+
+ private:
+  template <typename Callback>
+  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<CodeEntry*>& 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<CodeTreeConfig> 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<CodeEntry*> CodeEntryList;
+  CodeEntryList code_entries_;
+  // String::Hash -> const char*
+  HashMap resource_names_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_PROFILE_GENERATOR_H_
index 16fe25e..9c2287e 100644 (file)
@@ -58,16 +58,7 @@ bool SplayTree<Config, Allocator>::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<Config, Allocator>::Insert(const Key& key, Locator* locator) {
 
 
 template<typename Config, class Allocator>
-bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
+void SplayTree<Config, Allocator>::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<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::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<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
+  if (FindInternal(key)) {
     locator->bind(root_);
     return true;
   } else {
@@ -161,15 +173,38 @@ bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) {
 
 
 template<typename Config, class Allocator>
-bool SplayTree<Config, Allocator>::Remove(const Key& key) {
-  // Bail if the tree is empty
-  if (is_empty())
+bool SplayTree<Config, Allocator>::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<typename Config, class Allocator>
+bool SplayTree<Config, Allocator>::Remove(const Key& key) {
+  if (!FindInternal(key))
+    return false;
+  Node* node_to_remove = root_;
+  RemoveRootNode(key);
+  delete node_to_remove;
+  return true;
+}
+
+
+template<typename Config, class Allocator>
+void SplayTree<Config, Allocator>::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<Config, Allocator>::Remove(const Key& key) {
     // root.
     root_->right_ = right;
   }
-  return true;
 }
 
 
index b0f415d..c265276 100644 (file)
@@ -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 Callback>
   class NodeToPairAdaptor BASE_EMBEDDED {
index e35d454..f4964ae 100644 (file)
@@ -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 (file)
index 0000000..2d673d4
--- /dev/null
@@ -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<CodeEntry*> 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<CodeEntry*> 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<CodeEntry*> 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<CodeEntry*> 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<CodeEntry*> e1_path_vec(
+      e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
+  CodeEntry* e1_e2_path[] = {&entry1, &entry2};
+  Vector<CodeEntry*> 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<CodeEntry*> e2_path_vec(
+      e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
+  StaticNameCodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc");
+  CodeEntry* e3_path[] = {&entry3};
+  Vector<CodeEntry*> 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<i::Address>(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)));
+}
index 4270b14..d859fb0 100644 (file)
         '../../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',
index 3ffd182..ccb197a 100644 (file)
                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 */; };
                9F11D99F105AF0A300EBE5B2 /* heap-profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-profiler.h"; sourceTree = "<group>"; };
                9F4B7B870FCC877A00DC4117 /* log-utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "log-utils.cc"; sourceTree = "<group>"; };
                9F4B7B880FCC877A00DC4117 /* log-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "log-utils.h"; sourceTree = "<group>"; };
+               9F73E3AE114E61A100F84A5A /* profile-generator-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "profile-generator-inl.h"; sourceTree = "<group>"; };
+               9F73E3AF114E61A100F84A5A /* profile-generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "profile-generator.cc"; sourceTree = "<group>"; };
+               9F73E3B0114E61A100F84A5A /* profile-generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "profile-generator.h"; sourceTree = "<group>"; };
                9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = "<group>"; };
                9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "func-name-inferrer.h"; sourceTree = "<group>"; };
                9FBE03DC10BD409900F8BFBA /* fast-codegen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "fast-codegen.cc"; sourceTree = "<group>"; };
                                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 */,
                                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;
                };
                                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;
                };
index 1a7e14c..37ea01c 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\profile-generator.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\profile-generator.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\profile-generator-inl.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\platform-win32.cc"
                                >
                        </File>
index 346c5eb..de2d65a 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\profile-generator.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\profile-generator.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\profile-generator-inl.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\platform-win32.cc"
                                >
                        </File>
index 120dd19..29f4ed7 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\profile-generator.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\profile-generator.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\profile-generator-inl.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\platform-win32.cc"
                                >
                        </File>