Commit 983ab01a authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[utils,diagnostics] Remove SplayTree and its last use

The last use of V8's SplayTree was in diagnostics and is now replaced
by std::map.

Bug: v8:9359
Change-Id: I7b79fe619eb734343579652058be4d2b81fd4a1e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1664060
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62276}
parent 4c377520
......@@ -2840,8 +2840,6 @@ v8_source_set("v8_base_without_compiler") {
"src/utils/ostreams.cc",
"src/utils/ostreams.h",
"src/utils/pointer-with-payload.h",
"src/utils/splay-tree-inl.h",
"src/utils/splay-tree.h",
"src/utils/utils-inl.h",
"src/utils/utils.cc",
"src/utils/utils.h",
......
......@@ -4,6 +4,7 @@
#include "src/diagnostics/gdb-jit.h"
#include <map>
#include <memory>
#include <vector>
......@@ -17,7 +18,6 @@
#include "src/objects/objects.h"
#include "src/snapshot/natives.h"
#include "src/utils/ostreams.h"
#include "src/utils/splay-tree-inl.h"
#include "src/utils/vector.h"
#include "src/zone/zone-chunk-list.h"
......@@ -1822,23 +1822,24 @@ struct AddressRange {
Address end;
};
struct SplayTreeConfig {
struct AddressRangeLess {
bool operator()(const AddressRange& a, const AddressRange& b) const {
if (a.start == b.start) return a.end < b.end;
return a.start < b.start;
}
};
struct CodeMapConfig {
using Key = AddressRange;
using Value = JITCodeEntry*;
static const AddressRange kNoKey;
static Value NoValue() { return nullptr; }
static int Compare(const AddressRange& a, const AddressRange& b) {
// ptrdiff_t probably doesn't fit in an int.
if (a.start < b.start) return -1;
if (a.start == b.start) return 0;
return 1;
}
using Less = AddressRangeLess;
};
const AddressRange SplayTreeConfig::kNoKey = {0, 0};
using CodeMap = SplayTree<SplayTreeConfig>;
using CodeMap =
std::map<CodeMapConfig::Key, CodeMapConfig::Value, CodeMapConfig::Less>;
static CodeMap* GetCodeMap() {
// TODO(jgruber): Don't leak.
static CodeMap* code_map = nullptr;
if (code_map == nullptr) code_map = new CodeMap();
return code_map;
......@@ -1909,37 +1910,49 @@ static void AddUnwindInfo(CodeDescription* desc) {
static base::LazyMutex mutex = LAZY_MUTEX_INITIALIZER;
// Remove entries from the splay tree that intersect the given address range,
// Remove entries from the map that intersect the given address range,
// and deregister them from GDB.
static void RemoveJITCodeEntries(CodeMap* map, const AddressRange& range) {
DCHECK(range.start < range.end);
CodeMap::Locator cur;
if (map->FindGreatestLessThan(range, &cur) || map->FindLeast(&cur)) {
// Skip entries that are entirely less than the range of interest.
while (cur.key().end <= range.start) {
// CodeMap::FindLeastGreaterThan succeeds for entries whose key is greater
// than _or equal to_ the given key, so we have to advance our key to get
// the next one.
AddressRange new_key;
new_key.start = cur.key().end;
new_key.end = 0;
if (!map->FindLeastGreaterThan(new_key, &cur)) return;
}
// Evict intersecting ranges.
while (cur.key().start < range.end) {
AddressRange old_range = cur.key();
JITCodeEntry* old_entry = cur.value();
UnregisterCodeEntry(old_entry);
DestroyCodeEntry(old_entry);
if (map->empty()) return;
// Find the first overlapping entry.
CHECK(map->Remove(old_range));
if (!map->FindLeastGreaterThan(old_range, &cur)) return;
// If successful, points to the first element not less than `range`. The
// returned iterator has the key in `first` and the value in `second`.
auto it = map->lower_bound(range);
auto start_it = it;
if (it == map->end()) {
start_it = map->begin();
} else if (it != map->begin()) {
for (--it; it != map->begin(); --it) {
if ((*it).first.end <= range.start) break;
start_it = it;
}
}
DCHECK(start_it != map->end());
// Find the first non-overlapping entry after `range`.
const auto end_it = map->lower_bound({range.end, 0});
// Evict intersecting ranges.
if (std::distance(start_it, end_it) < 1) return; // No overlapping entries.
for (auto it = start_it; it != end_it; it++) {
JITCodeEntry* old_entry = (*it).second;
UnregisterCodeEntry(old_entry);
DestroyCodeEntry(old_entry);
}
map->erase(start_it, end_it);
}
// Insert the entry into the splay tree and register it with GDB.
// Insert the entry into the map and register it with GDB.
static void AddJITCodeEntry(CodeMap* map, const AddressRange& range,
JITCodeEntry* entry, bool dump_if_enabled,
const char* name_hint) {
......@@ -1956,9 +1969,9 @@ static void AddJITCodeEntry(CodeMap* map, const AddressRange& range,
}
#endif
CodeMap::Locator cur;
CHECK(map->Insert(range, &cur));
cur.set_value(entry);
auto result = map->emplace(range, entry);
DCHECK(result.second); // Insertion happened.
USE(result);
RegisterCodeEntry(entry);
}
......
// Copyright 2010 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UTILS_SPLAY_TREE_INL_H_
#define V8_UTILS_SPLAY_TREE_INL_H_
#include <vector>
#include "src/utils/splay-tree.h"
namespace v8 {
namespace internal {
template<typename Config, class Allocator>
SplayTree<Config, Allocator>::~SplayTree() {
NodeDeleter deleter;
ForEachNode(&deleter);
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::Insert(const Key& key,
Locator* locator) {
if (is_empty()) {
// If the tree is empty, insert the new node.
root_ = new(allocator_) Node(key, Config::NoValue());
} else {
// Splay on the key to move the last node on the search path
// for the key to the root of the tree.
Splay(key);
// Ignore repeated insertions with the same key.
int cmp = Config::Compare(key, root_->key_);
if (cmp == 0) {
locator->bind(root_);
return false;
}
// Insert the new node.
Node* node = new(allocator_) Node(key, Config::NoValue());
InsertInternal(cmp, node);
}
locator->bind(root_);
return true;
}
template<typename Config, class Allocator>
void SplayTree<Config, Allocator>::InsertInternal(int cmp, Node* node) {
if (cmp > 0) {
node->left_ = root_;
node->right_ = root_->right_;
root_->right_ = nullptr;
} else {
node->right_ = root_;
node->left_ = root_->left_;
root_->left_ = nullptr;
}
root_ = node;
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::FindInternal(const Key& key) {
if (is_empty())
return false;
Splay(key);
return Config::Compare(key, root_->key_) == 0;
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::Contains(const Key& key) {
return FindInternal(key);
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
if (FindInternal(key)) {
locator->bind(root_);
return true;
} else {
return false;
}
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::FindGreatestLessThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the greatest node in
// the left subtree.
int cmp = Config::Compare(root_->key_, key);
if (cmp <= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->left_;
bool result = FindGreatest(locator);
root_ = temp;
return result;
}
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::FindLeastGreaterThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the least node in
// the right subtree.
int cmp = Config::Compare(root_->key_, key);
if (cmp >= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->right_;
bool result = FindLeast(locator);
root_ = temp;
return result;
}
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::FindGreatest(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->right_ != nullptr) current = current->right_;
locator->bind(current);
return true;
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->left_ != nullptr) current = current->left_;
locator->bind(current);
return true;
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::Move(const Key& old_key,
const Key& new_key) {
if (!FindInternal(old_key))
return false;
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_ == nullptr) {
// No left child, so the new tree is just the right child.
root_ = root_->right_;
} else {
// Left child exists.
Node* right = root_->right_;
// Make the original left child the new root.
root_ = root_->left_;
// Splay to make sure that the new root has an empty right child.
Splay(key);
// Insert the original right child as the right child of the new
// root.
root_->right_ = right;
}
}
template<typename Config, class Allocator>
void SplayTree<Config, Allocator>::Splay(const Key& key) {
if (is_empty())
return;
Node dummy_node(Config::kNoKey, Config::NoValue());
// Create a dummy node. The use of the dummy node is a bit
// counter-intuitive: The right child of the dummy node will hold
// the L tree of the algorithm. The left child of the dummy node
// will hold the R tree of the algorithm. Using a dummy node, left
// and right will always be nodes and we avoid special cases.
Node* dummy = &dummy_node;
Node* left = dummy;
Node* right = dummy;
Node* current = root_;
while (true) {
int cmp = Config::Compare(key, current->key_);
if (cmp < 0) {
if (current->left_ == nullptr) break;
if (Config::Compare(key, current->left_->key_) < 0) {
// Rotate right.
Node* temp = current->left_;
current->left_ = temp->right_;
temp->right_ = current;
current = temp;
if (current->left_ == nullptr) break;
}
// Link right.
right->left_ = current;
right = current;
current = current->left_;
} else if (cmp > 0) {
if (current->right_ == nullptr) break;
if (Config::Compare(key, current->right_->key_) > 0) {
// Rotate left.
Node* temp = current->right_;
current->right_ = temp->left_;
temp->left_ = current;
current = temp;
if (current->right_ == nullptr) break;
}
// Link left.
left->right_ = current;
left = current;
current = current->right_;
} else {
break;
}
}
// Assemble.
left->right_ = current->left_;
right->left_ = current->right_;
current->left_ = dummy->right_;
current->right_ = dummy->left_;
root_ = current;
}
template <typename Config, class Allocator> template <class Callback>
void SplayTree<Config, Allocator>::ForEach(Callback* callback) {
NodeToPairAdaptor<Callback> callback_adaptor(callback);
ForEachNode(&callback_adaptor);
}
template <typename Config, class Allocator> template <class Callback>
void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) {
if (root_ == nullptr) return;
// Pre-allocate some space for tiny trees.
std::vector<Node*> nodes_to_visit;
nodes_to_visit.push_back(root_);
size_t pos = 0;
while (pos < nodes_to_visit.size()) {
Node* node = nodes_to_visit[pos++];
if (node->left() != nullptr) nodes_to_visit.push_back(node->left());
if (node->right() != nullptr) nodes_to_visit.push_back(node->right());
callback->Call(node);
}
}
} // namespace internal
} // namespace v8
#endif // V8_UTILS_SPLAY_TREE_INL_H_
// Copyright 2010 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UTILS_SPLAY_TREE_H_
#define V8_UTILS_SPLAY_TREE_H_
#include "src/utils/allocation.h"
namespace v8 {
namespace internal {
// A splay tree. The config type parameter encapsulates the different
// configurations of a concrete splay tree:
//
// typedef Key: the key type
// typedef Value: the value type
// static const Key kNoKey: the dummy key used when no key is set
// static Value kNoValue(): the dummy value used to initialize nodes
// static int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
//
// The tree is also parameterized by an allocation policy
// (Allocator). The policy is used for allocating lists in the C free
// store or the zone; see zone.h.
// Forward defined as
// template <typename Config, class Allocator = FreeStoreAllocationPolicy>
// class SplayTree;
template <typename Config, class AllocationPolicy>
class SplayTree {
public:
using Key = typename Config::Key;
using Value = typename Config::Value;
class Locator;
explicit SplayTree(AllocationPolicy allocator = AllocationPolicy())
: root_(nullptr), allocator_(allocator) {}
~SplayTree();
V8_INLINE void* operator new(
size_t size, AllocationPolicy allocator = AllocationPolicy()) {
return allocator.New(static_cast<int>(size));
}
V8_INLINE void operator delete(void* p) { AllocationPolicy::Delete(p); }
// Please the MSVC compiler. We should never have to execute this.
V8_INLINE void operator delete(void* p, AllocationPolicy policy) {
UNREACHABLE();
}
AllocationPolicy allocator() { return allocator_; }
// Checks if there is a mapping for the key.
bool Contains(const Key& key);
// Inserts the given key in this tree with the given value. Returns
// true if a node was inserted, otherwise false. If found the locator
// is enabled and provides access to the mapping for the key.
bool Insert(const Key& key, Locator* locator);
// Looks up the key in this tree and returns true if it was found,
// otherwise false. If the node is found the locator is enabled and
// provides access to the mapping for the key.
bool Find(const Key& key, Locator* locator);
// Finds the mapping with the greatest key less than or equal to the
// given key.
bool FindGreatestLessThan(const Key& key, Locator* locator);
// Find the mapping with the greatest key in this tree.
bool FindGreatest(Locator* locator);
// Finds the mapping with the least key greater than or equal to the
// given key.
bool FindLeastGreaterThan(const Key& key, Locator* locator);
// 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);
// Remove all keys from the tree.
void Clear() { ResetRoot(); }
bool is_empty() { return root_ == nullptr; }
// Perform the splay operation for the given key. Moves the node with
// the given key to the top of the tree. If no node has the given
// key, the last node on the search path is moved to the top of the
// tree.
void Splay(const Key& key);
class Node {
public:
Node(const Key& key, const Value& value)
: key_(key), value_(value), left_(nullptr), right_(nullptr) {}
V8_INLINE void* operator new(size_t size, AllocationPolicy allocator) {
return allocator.New(static_cast<int>(size));
}
V8_INLINE void operator delete(void* p) {
return AllocationPolicy::Delete(p);
}
// Please the MSVC compiler. We should never have to execute
// this.
V8_INLINE void operator delete(void* p, AllocationPolicy allocator) {
UNREACHABLE();
}
Key key() { return key_; }
Value value() { return value_; }
Node* left() { return left_; }
Node* right() { return right_; }
private:
friend class SplayTree;
friend class Locator;
Key key_;
Value value_;
Node* left_;
Node* right_;
};
// A locator provides access to a node in the tree without actually
// exposing the node.
class Locator {
public:
explicit Locator(Node* node) : node_(node) {}
Locator() : node_(nullptr) {}
const Key& key() { return node_->key_; }
Value& value() { return node_->value_; }
void set_value(const Value& value) { node_->value_ = value; }
inline void bind(Node* node) { node_ = node; }
private:
Node* node_;
};
template <class Callback>
void ForEach(Callback* callback);
protected:
// Resets tree root. Existing nodes become unreachable.
void ResetRoot() { root_ = nullptr; }
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 {
public:
explicit NodeToPairAdaptor(Callback* callback) : callback_(callback) {}
void Call(Node* node) { callback_->Call(node->key(), node->value()); }
private:
Callback* callback_;
DISALLOW_COPY_AND_ASSIGN(NodeToPairAdaptor);
};
class NodeDeleter {
public:
NodeDeleter() = default;
void Call(Node* node) { AllocationPolicy::Delete(node); }
private:
DISALLOW_COPY_AND_ASSIGN(NodeDeleter);
};
template <class Callback>
void ForEachNode(Callback* callback);
Node* root_;
AllocationPolicy allocator_;
DISALLOW_COPY_AND_ASSIGN(SplayTree);
};
} // namespace internal
} // namespace v8
#endif // V8_UTILS_SPLAY_TREE_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment