New zone-backed list datastructure to replace ZoneList
Since ZoneLists are essentially non-standard ZoneVectors and have a bad growing behaviour (ZoneList-allocations make up ~50% of website parse zone memory) we should stop using them. The zone-containers are merely a clean-up, with none of them actually better suited to be used with zones. This new datastructure allows most operations of a LinkedList ( except pop_first and insertAt/removeAt) but uses about the same memory as a well-initialized ZoneVector/ZoneList (<3% overhead with reasonably large lists). It also never attempts to free memory again (which would not work in zones anyway). The ZoneChunkList is essentially a doubly-linked-list of arrays of variable size. Some test-results where I tried storing 16k pointers in different list types (lists themselves also zone-allocated): List type Zone memory used Time taken ----------------------------------------------------------------------- Zone array (for comparison) 131072 B Ideally initialized ZoneList 131088 B 0.062ms ChunkZoneList 134744 B 0.052ms <--new thing ZoneDeque 141744 B ZoneLinkedList 393264 B Initially empty ZoneList 524168 B 0.171ms <--right now ChunkZoneList only push_front 524320 B Review-Url: https://codereview.chromium.org/2449383002 Cr-Commit-Position: refs/heads/master@{#40602}
This commit is contained in:
parent
24d38be132
commit
610c0d75c8
1
BUILD.gn
1
BUILD.gn
@ -1737,6 +1737,7 @@ v8_source_set("v8_base") {
|
||||
"src/zone/accounting-allocator.h",
|
||||
"src/zone/zone-allocator.h",
|
||||
"src/zone/zone-allocator.h",
|
||||
"src/zone/zone-chunk-list.h",
|
||||
"src/zone/zone-containers.h",
|
||||
"src/zone/zone-segment.cc",
|
||||
"src/zone/zone-segment.h",
|
||||
|
@ -1279,6 +1279,7 @@
|
||||
'zone/zone-segment.h',
|
||||
'zone/zone.cc',
|
||||
'zone/zone.h',
|
||||
'zone/zone-chunk-list.h',
|
||||
'zone/zone-segment.cc',
|
||||
'zone/zone-segment.h',
|
||||
'zone/zone-allocator.h',
|
||||
|
437
src/zone/zone-chunk-list.h
Normal file
437
src/zone/zone-chunk-list.h
Normal file
@ -0,0 +1,437 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/globals.h"
|
||||
#include "src/zone/zone.h"
|
||||
|
||||
#ifndef V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
|
||||
#define V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
class ZoneChunkListIterator;
|
||||
template <typename T>
|
||||
class ForwardZoneChunkListIterator;
|
||||
template <typename T>
|
||||
class ReverseZoneChunkListIterator;
|
||||
|
||||
// A zone-backed hybrid of a vector and a linked list. Use it if you need a
|
||||
// collection that
|
||||
// * needs to grow indefinitely,
|
||||
// * will mostly grow at the back, but may sometimes grow in front as well
|
||||
// (preferrably in batches),
|
||||
// * needs to have very low overhead,
|
||||
// * offers forward- and backwards-iteration,
|
||||
// * offers relatively fast seeking,
|
||||
// * offers bidirectional iterators,
|
||||
// * can be rewound without freeing the backing store.
|
||||
// This list will maintain a doubly-linked list of chunks. When a chunk is
|
||||
// filled up, a new one gets appended. New chunks appended at the end will
|
||||
// grow in size up to a certain limit to avoid over-allocation and to keep
|
||||
// the zone clean.
|
||||
template <typename T>
|
||||
class ZoneChunkList : public ZoneObject {
|
||||
public:
|
||||
enum class StartMode {
|
||||
// The list will not allocate a starting chunk. Use if you expect your
|
||||
// list to remain empty in many cases.
|
||||
kEmpty = 0,
|
||||
// The list will start with a small initial chunk. Subsequent chunks will
|
||||
// get bigger over time.
|
||||
kSmall = 8,
|
||||
// The list will start with one chunk at maximum size. Use this if you
|
||||
// expect your list to contain many items to avoid growing chunks.
|
||||
kBig = 256
|
||||
};
|
||||
|
||||
explicit ZoneChunkList(Zone* zone, StartMode start_mode = StartMode::kEmpty)
|
||||
: zone_(zone) {
|
||||
if (start_mode != StartMode::kEmpty) {
|
||||
front_ = NewChunk(static_cast<uint32_t>(start_mode));
|
||||
back_ = front_;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const;
|
||||
|
||||
T& front() const;
|
||||
T& back() const;
|
||||
|
||||
void push_back(const T& item);
|
||||
void pop_back();
|
||||
|
||||
// Will push a separate chunk to the front of the chunk-list.
|
||||
// Very memory-inefficient. Do only use sparsely! If you have many items to
|
||||
// add in front, consider using 'push_front_many'.
|
||||
void push_front(const T& item);
|
||||
// TODO(heimbuef): Add 'push_front_many'.
|
||||
|
||||
// Cuts the last list elements so at most 'limit' many remain. Does not
|
||||
// free the actual memory, since it is zone allocated.
|
||||
void Rewind(const size_t limit = 0);
|
||||
|
||||
// Quickly scans the list to retrieve the element at the given index. Will
|
||||
// *not* check bounds.
|
||||
ForwardZoneChunkListIterator<T> Find(const size_t index);
|
||||
ForwardZoneChunkListIterator<const T> Find(const size_t index) const;
|
||||
// TODO(heimbuef): Add 'rFind', seeking from the end and returning a
|
||||
// reverse iterator.
|
||||
|
||||
ForwardZoneChunkListIterator<T> begin();
|
||||
ForwardZoneChunkListIterator<T> end();
|
||||
ReverseZoneChunkListIterator<T> rbegin();
|
||||
ReverseZoneChunkListIterator<T> rend();
|
||||
ForwardZoneChunkListIterator<const T> begin() const;
|
||||
ForwardZoneChunkListIterator<const T> end() const;
|
||||
ReverseZoneChunkListIterator<const T> rbegin() const;
|
||||
ReverseZoneChunkListIterator<const T> rend() const;
|
||||
|
||||
private:
|
||||
friend class ZoneChunkListIterator<T>;
|
||||
friend class ForwardZoneChunkListIterator<T>;
|
||||
friend class ReverseZoneChunkListIterator<T>;
|
||||
static const uint32_t kMaxChunkCapacity = 256u;
|
||||
|
||||
STATIC_ASSERT(kMaxChunkCapacity == static_cast<uint32_t>(StartMode::kBig));
|
||||
|
||||
struct Chunk {
|
||||
uint32_t capacity_ = 0;
|
||||
uint32_t position_ = 0;
|
||||
Chunk* next_ = nullptr;
|
||||
Chunk* previous_ = nullptr;
|
||||
T* items() { return reinterpret_cast<T*>(this + 1); }
|
||||
};
|
||||
|
||||
Chunk* NewChunk(const uint32_t capacity) {
|
||||
Chunk* chunk =
|
||||
new (zone_->New(sizeof(Chunk) + capacity * sizeof(T))) Chunk();
|
||||
chunk->capacity_ = capacity;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
struct SeekResult {
|
||||
Chunk* chunk_;
|
||||
uint32_t chunk_index_;
|
||||
};
|
||||
|
||||
// Returns the chunk and relative index of the element at the given global
|
||||
// index. Will skip entire chunks and is therefore faster than iterating.
|
||||
SeekResult SeekIndex(size_t index) const;
|
||||
|
||||
Zone* zone_;
|
||||
|
||||
size_t size_ = 0;
|
||||
Chunk* front_ = nullptr;
|
||||
Chunk* back_ = nullptr;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ZoneChunkList);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ZoneChunkListIterator {
|
||||
public:
|
||||
T& operator*() { return current_->items()[position_]; }
|
||||
bool operator==(const ZoneChunkListIterator& other) {
|
||||
return other.current_ == current_ && other.position_ == position_;
|
||||
}
|
||||
bool operator!=(const ZoneChunkListIterator& other) {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
protected:
|
||||
ZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
|
||||
size_t position)
|
||||
: current_(current), position_(position) {}
|
||||
|
||||
void MoveNext() {
|
||||
++position_;
|
||||
if (position_ >= current_->capacity_) {
|
||||
current_ = current_->next_;
|
||||
position_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MoveRNext() {
|
||||
if (position_ == 0) {
|
||||
current_ = current_->previous_;
|
||||
position_ = current_ ? current_->capacity_ - 1 : 0;
|
||||
} else {
|
||||
--position_;
|
||||
}
|
||||
}
|
||||
|
||||
typename ZoneChunkList<T>::Chunk* current_;
|
||||
size_t position_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ForwardZoneChunkListIterator : public ZoneChunkListIterator<T> {
|
||||
using ZoneChunkListIterator<T>::current_;
|
||||
using ZoneChunkListIterator<T>::position_;
|
||||
using ZoneChunkListIterator<T>::MoveNext;
|
||||
using ZoneChunkListIterator<T>::MoveRNext;
|
||||
|
||||
public:
|
||||
ForwardZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
|
||||
size_t position)
|
||||
: ZoneChunkListIterator<T>(current, position) {}
|
||||
|
||||
ForwardZoneChunkListIterator& operator++() {
|
||||
MoveNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ForwardZoneChunkListIterator operator++(int) {
|
||||
ForwardZoneChunkListIterator<T> clone(*this);
|
||||
MoveNext();
|
||||
return clone;
|
||||
}
|
||||
|
||||
ForwardZoneChunkListIterator& operator--() {
|
||||
MoveRNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ForwardZoneChunkListIterator operator--(int) {
|
||||
ForwardZoneChunkListIterator<T> clone(*this);
|
||||
MoveRNext();
|
||||
return clone;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ZoneChunkList<T>;
|
||||
static ForwardZoneChunkListIterator<T> Begin(ZoneChunkList<T>* list) {
|
||||
return ForwardZoneChunkListIterator<T>(list->front_, 0);
|
||||
}
|
||||
static ForwardZoneChunkListIterator<T> End(ZoneChunkList<T>* list) {
|
||||
if (list->back_ == nullptr) return Begin(list);
|
||||
|
||||
DCHECK_LE(list->back_->position_, list->back_->capacity_);
|
||||
if (list->back_->position_ == list->back_->capacity_) {
|
||||
return ForwardZoneChunkListIterator<T>(nullptr, 0);
|
||||
}
|
||||
|
||||
return ForwardZoneChunkListIterator<T>(list->back_, list->back_->position_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ReverseZoneChunkListIterator : public ZoneChunkListIterator<T> {
|
||||
using ZoneChunkListIterator<T>::current_;
|
||||
using ZoneChunkListIterator<T>::position_;
|
||||
using ZoneChunkListIterator<T>::MoveNext;
|
||||
using ZoneChunkListIterator<T>::MoveRNext;
|
||||
|
||||
public:
|
||||
ReverseZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
|
||||
size_t position)
|
||||
: ZoneChunkListIterator<T>(current, position) {}
|
||||
|
||||
ReverseZoneChunkListIterator& operator++() {
|
||||
MoveRNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseZoneChunkListIterator operator++(int) {
|
||||
ReverseZoneChunkListIterator<T> clone(*this);
|
||||
MoveRNext();
|
||||
return clone;
|
||||
}
|
||||
|
||||
ReverseZoneChunkListIterator& operator--() {
|
||||
MoveNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseZoneChunkListIterator operator--(int) {
|
||||
ForwardZoneChunkListIterator<T> clone(*this);
|
||||
MoveNext();
|
||||
return clone;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ZoneChunkList<T>;
|
||||
static ReverseZoneChunkListIterator<T> Begin(ZoneChunkList<T>* list) {
|
||||
if (list->back_ == nullptr) return End(list);
|
||||
if (list->back_->position_ == 0) {
|
||||
if (list->back_->previous_ != nullptr) {
|
||||
return ReverseZoneChunkListIterator<T>(
|
||||
list->back_->previous_, list->back_->previous_->capacity_ - 1);
|
||||
} else {
|
||||
return End(list);
|
||||
}
|
||||
}
|
||||
return ReverseZoneChunkListIterator<T>(list->back_,
|
||||
list->back_->position_ - 1);
|
||||
}
|
||||
static ReverseZoneChunkListIterator<T> End(ZoneChunkList<T>* list) {
|
||||
return ReverseZoneChunkListIterator<T>(nullptr, 0);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
size_t ZoneChunkList<T>::size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& ZoneChunkList<T>::front() const {
|
||||
DCHECK_LT(size_t(0), size());
|
||||
return front_->items()[0];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& ZoneChunkList<T>::back() const {
|
||||
DCHECK_LT(size_t(0), size());
|
||||
|
||||
if (back_->position_ == 0) {
|
||||
return back_->previous_->items()[back_->previous_->position_ - 1];
|
||||
} else {
|
||||
return back_->items()[back_->position_ - 1];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ZoneChunkList<T>::push_back(const T& item) {
|
||||
if (back_ == nullptr) {
|
||||
front_ = NewChunk(static_cast<uint32_t>(StartMode::kSmall));
|
||||
back_ = front_;
|
||||
}
|
||||
|
||||
DCHECK_LE(back_->position_, back_->capacity_);
|
||||
if (back_->position_ == back_->capacity_) {
|
||||
if (back_->next_ == nullptr) {
|
||||
Chunk* chunk = NewChunk(Min(back_->capacity_ << 1, kMaxChunkCapacity));
|
||||
back_->next_ = chunk;
|
||||
chunk->previous_ = back_;
|
||||
}
|
||||
back_ = back_->next_;
|
||||
}
|
||||
back_->items()[back_->position_] = item;
|
||||
++back_->position_;
|
||||
++size_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ZoneChunkList<T>::pop_back() {
|
||||
DCHECK_LT(size_t(0), size());
|
||||
if (back_->position_ == 0) {
|
||||
back_ = back_->previous_;
|
||||
}
|
||||
--back_->position_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ZoneChunkList<T>::push_front(const T& item) {
|
||||
Chunk* chunk = NewChunk(1); // Yes, this gets really inefficient.
|
||||
chunk->next_ = front_;
|
||||
if (front_) {
|
||||
front_->previous_ = chunk;
|
||||
} else {
|
||||
back_ = chunk;
|
||||
}
|
||||
front_ = chunk;
|
||||
|
||||
chunk->items()[0] = item;
|
||||
chunk->position_ = 1;
|
||||
++size_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename ZoneChunkList<T>::SeekResult ZoneChunkList<T>::SeekIndex(
|
||||
size_t index) const {
|
||||
DCHECK_LT(index, size());
|
||||
Chunk* current = front_;
|
||||
while (index > current->capacity_) {
|
||||
index -= current->capacity_;
|
||||
current = current->next_;
|
||||
}
|
||||
return {current, static_cast<uint32_t>(index)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ZoneChunkList<T>::Rewind(const size_t limit) {
|
||||
if (limit >= size()) return;
|
||||
|
||||
SeekResult seek_result = SeekIndex(limit);
|
||||
DCHECK_NOT_NULL(seek_result.chunk_);
|
||||
|
||||
// Do a partial rewind of the chunk containing the index.
|
||||
seek_result.chunk_->position_ = seek_result.chunk_index_;
|
||||
|
||||
// Set back_ so iterators will work correctly.
|
||||
back_ = seek_result.chunk_;
|
||||
|
||||
// Do full rewind of all subsequent chunks.
|
||||
for (Chunk* current = seek_result.chunk_->next_; current != nullptr;
|
||||
current = current->next_) {
|
||||
current->position_ = 0;
|
||||
}
|
||||
|
||||
size_ = limit;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ForwardZoneChunkListIterator<T> ZoneChunkList<T>::Find(const size_t index) {
|
||||
SeekResult seek_result = SeekIndex(index);
|
||||
return ForwardZoneChunkListIterator<T>(seek_result.chunk_,
|
||||
seek_result.chunk_index_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::Find(
|
||||
const size_t index) const {
|
||||
SeekResult seek_result = SeekIndex(index);
|
||||
return ForwardZoneChunkListIterator<const T>(seek_result.chunk_,
|
||||
seek_result.chunk_index_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ForwardZoneChunkListIterator<T> ZoneChunkList<T>::begin() {
|
||||
return ForwardZoneChunkListIterator<T>::Begin(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ForwardZoneChunkListIterator<T> ZoneChunkList<T>::end() {
|
||||
return ForwardZoneChunkListIterator<T>::End(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ReverseZoneChunkListIterator<T> ZoneChunkList<T>::rbegin() {
|
||||
return ReverseZoneChunkListIterator<T>::Begin(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ReverseZoneChunkListIterator<T> ZoneChunkList<T>::rend() {
|
||||
return ReverseZoneChunkListIterator<T>::End(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::begin() const {
|
||||
return ForwardZoneChunkListIterator<const T>::Begin(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::end() const {
|
||||
return ForwardZoneChunkListIterator<const T>::End(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ReverseZoneChunkListIterator<const T> ZoneChunkList<T>::rbegin() const {
|
||||
return ReverseZoneChunkListIterator<const T>::Begin(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ReverseZoneChunkListIterator<const T> ZoneChunkList<T>::rend() const {
|
||||
return ReverseZoneChunkListIterator<const T>::End(this);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
|
@ -131,6 +131,7 @@ v8_executable("unittests") {
|
||||
"wasm/wasm-macro-gen-unittest.cc",
|
||||
"wasm/wasm-module-builder-unittest.cc",
|
||||
"zone/segmentpool-unittest.cc",
|
||||
"zone/zone-chunk-list-unittest.cc",
|
||||
]
|
||||
|
||||
if (v8_current_cpu == "arm") {
|
||||
|
@ -119,6 +119,7 @@
|
||||
'test-utils.cc',
|
||||
'value-serializer-unittest.cc',
|
||||
'zone/segmentpool-unittest.cc',
|
||||
'zone/zone-chunk-list-unittest.cc',
|
||||
'wasm/asm-types-unittest.cc',
|
||||
'wasm/ast-decoder-unittest.cc',
|
||||
'wasm/control-transfer-unittest.cc',
|
||||
|
144
test/unittests/zone/zone-chunk-list-unittest.cc
Normal file
144
test/unittests/zone/zone-chunk-list-unittest.cc
Normal file
@ -0,0 +1,144 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#include "src/zone/zone-chunk-list.h"
|
||||
|
||||
#include "src/list-inl.h"
|
||||
#include "src/zone/accounting-allocator.h"
|
||||
#include "src/zone/zone.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const size_t kItemCount = size_t(1) << 10;
|
||||
|
||||
TEST(ZoneChunkList, ForwardIterationTest) {
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
|
||||
ZoneChunkList<uintptr_t> zone_chunk_list(&zone);
|
||||
|
||||
for (size_t i = 0; i < kItemCount; ++i) {
|
||||
zone_chunk_list.push_back(static_cast<uintptr_t>(i));
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
for (uintptr_t item : zone_chunk_list) {
|
||||
EXPECT_EQ(static_cast<size_t>(item), count);
|
||||
count++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, kItemCount);
|
||||
}
|
||||
|
||||
TEST(ZoneChunkList, ReverseIterationTest) {
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
|
||||
ZoneChunkList<uintptr_t> zone_chunk_list(&zone);
|
||||
|
||||
for (size_t i = 0; i < kItemCount; ++i) {
|
||||
zone_chunk_list.push_back(static_cast<uintptr_t>(i));
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
for (auto it = zone_chunk_list.rbegin(); it != zone_chunk_list.rend(); ++it) {
|
||||
EXPECT_EQ(static_cast<size_t>(*it), kItemCount - count - 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, kItemCount);
|
||||
}
|
||||
|
||||
TEST(ZoneChunkList, PushFrontTest) {
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
|
||||
ZoneChunkList<uintptr_t> zone_chunk_list(&zone);
|
||||
|
||||
for (size_t i = 0; i < kItemCount; ++i) {
|
||||
zone_chunk_list.push_front(static_cast<uintptr_t>(i));
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
for (uintptr_t item : zone_chunk_list) {
|
||||
EXPECT_EQ(static_cast<size_t>(item), kItemCount - count - 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, kItemCount);
|
||||
}
|
||||
|
||||
TEST(ZoneChunkList, RewindTest) {
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
|
||||
ZoneChunkList<uintptr_t> zone_chunk_list(&zone);
|
||||
|
||||
for (size_t i = 0; i < kItemCount; ++i) {
|
||||
zone_chunk_list.push_back(static_cast<uintptr_t>(i));
|
||||
}
|
||||
|
||||
zone_chunk_list.Rewind(42);
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
for (uintptr_t item : zone_chunk_list) {
|
||||
EXPECT_EQ(static_cast<size_t>(item), count);
|
||||
count++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, 42);
|
||||
EXPECT_EQ(count, zone_chunk_list.size());
|
||||
|
||||
zone_chunk_list.Rewind(0);
|
||||
|
||||
count = 0;
|
||||
|
||||
for (uintptr_t item : zone_chunk_list) {
|
||||
USE(item);
|
||||
count++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, 0);
|
||||
EXPECT_EQ(count, zone_chunk_list.size());
|
||||
|
||||
zone_chunk_list.Rewind(100);
|
||||
|
||||
count = 0;
|
||||
|
||||
for (uintptr_t item : zone_chunk_list) {
|
||||
EXPECT_EQ(static_cast<size_t>(item), count);
|
||||
count++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(count, 0);
|
||||
EXPECT_EQ(count, zone_chunk_list.size());
|
||||
}
|
||||
|
||||
TEST(ZoneChunkList, FindTest) {
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
|
||||
ZoneChunkList<uintptr_t> zone_chunk_list(&zone);
|
||||
|
||||
for (size_t i = 0; i < kItemCount; ++i) {
|
||||
zone_chunk_list.push_back(static_cast<uintptr_t>(i));
|
||||
}
|
||||
|
||||
const size_t index = kItemCount / 2 + 42;
|
||||
|
||||
EXPECT_EQ(*zone_chunk_list.Find(index), static_cast<uintptr_t>(index));
|
||||
|
||||
*zone_chunk_list.Find(index) = 42;
|
||||
|
||||
EXPECT_EQ(*zone_chunk_list.Find(index), 42);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
Loading…
Reference in New Issue
Block a user