Commit 14ed15e7 authored by dcarney@chromium.org's avatar dcarney@chromium.org

Make GlobalHandle::NodeBlock deletable

R=mstarzinger@chromium.org
BUG=

Review URL: https://codereview.chromium.org/21042004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16040 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 411d21b2
This diff is collapsed.
......@@ -156,6 +156,9 @@ class GlobalHandles {
return number_of_global_handles_;
}
// Returns the current number of allocated blocks
int block_count() const { return number_of_blocks_; }
// Clear the weakness of a global handle.
static void ClearWeakness(Object** location);
......@@ -275,11 +278,14 @@ class GlobalHandles {
#ifdef DEBUG
void PrintStats();
void Print();
void VerifyBlockInvariants();
#endif
private:
explicit GlobalHandles(Isolate* isolate);
void SortBlocks(bool shouldPrune);
// Migrates data from the internal representation (object_group_connections_,
// retainer_infos_ and implicit_ref_connections_) to the public and more
// efficient representation (object_groups_ and implicit_ref_groups_).
......@@ -293,20 +299,64 @@ class GlobalHandles {
class Node;
class NodeBlock;
class NodeIterator;
class BlockListIterator;
// Base class for NodeBlock
class BlockList {
public:
BlockList();
~BlockList() { ASSERT(IsDetached()); }
void Detach();
void InsertAsHead(BlockList* block) {
ASSERT(IsAnchor());
InsertAsNext(block);
}
void InsertAsTail(BlockList* block) {
ASSERT(IsAnchor());
prev_block_->InsertAsNext(block);
}
inline bool IsAnchor() { return first_free_ == NULL && used_nodes_ == 0; }
inline bool IsDetached() {
ASSERT_EQ(prev_block_ == this, next_block_ == this);
return prev_block_ == this;
}
bool HasAtLeastLength(int length);
bool IsUnused() { return used_nodes_ == 0; }
int used_nodes() const { return used_nodes_; }
BlockList* next() { return next_block_; }
BlockList* prev() { return prev_block_; }
#ifdef DEBUG
int LengthOfFreeList();
#endif
static void SortBlocks(GlobalHandles* global_handles, bool prune);
protected:
BlockList* prev_block_;
BlockList* next_block_;
Node* first_free_;
int used_nodes_;
private:
// Needed for quicksort
static int CompareBlocks(const void* a, const void* b);
void InsertAsNext(BlockList* block);
DISALLOW_COPY_AND_ASSIGN(BlockList);
};
Isolate* isolate_;
// Field always containing the number of blocks allocated.
int number_of_blocks_;
// Field always containing the number of handles to global objects.
int number_of_global_handles_;
// List of all allocated node blocks.
NodeBlock* first_block_;
// List of node blocks with used nodes.
NodeBlock* first_used_block_;
// Anchors for doubly linked lists of blocks
BlockList full_blocks_;
BlockList non_full_blocks_;
// Free list of nodes.
Node* first_free_;
// An array of all the anchors held by GlobalHandles.
// This simplifies iteration across all blocks.
static const int kAllAnchorsSize = 2;
BlockList* all_anchors_[kAllAnchorsSize];
// Contains all nodes holding new space objects. Note: when the list
// is accessed, some of the objects may have been promoted already.
......
......@@ -300,4 +300,57 @@ static inline void SimulateFullSpace(v8::internal::PagedSpace* space) {
}
// Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
class RandomNumberGenerator {
public:
RandomNumberGenerator() {
init();
}
void init(uint32_t seed = 0x5688c73e) {
static const uint32_t phi = 0x9e3779b9;
c = 362436;
i = kQSize-1;
Q[0] = seed;
Q[1] = seed + phi;
Q[2] = seed + phi + phi;
for (unsigned j = 3; j < kQSize; j++) {
Q[j] = Q[j - 3] ^ Q[j - 2] ^ phi ^ j;
}
}
uint32_t next() {
uint64_t a = 18782;
uint32_t r = 0xfffffffe;
i = (i + 1) & (kQSize-1);
uint64_t t = a * Q[i] + c;
c = (t >> 32);
uint32_t x = static_cast<uint32_t>(t + c);
if (x < c) {
x++;
c++;
}
return (Q[i] = r - x);
}
uint32_t next(int max) {
return next() % max;
}
bool next(double threshold) {
ASSERT(threshold >= 0.0 && threshold <= 1.0);
if (threshold == 1.0) return true;
if (threshold == 0.0) return false;
uint32_t value = next() % 100000;
return threshold > static_cast<double>(value)/100000.0;
}
private:
static const uint32_t kQSize = 4096;
uint32_t Q[kQSize];
uint32_t c;
uint32_t i;
};
#endif // ifndef CCTEST_H_
......@@ -25,6 +25,9 @@
// (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 <map>
#include <vector>
#include "global-handles.h"
#include "cctest.h"
......@@ -315,3 +318,154 @@ TEST(ImplicitReferences) {
ASSERT(implicit_refs->at(1)->length == 1);
ASSERT(implicit_refs->at(1)->children[0] == g2c1.location());
}
static const int kBlockSize = 256;
TEST(BlockCollection) {
v8::V8::Initialize();
Isolate* isolate = Isolate::Current();
GlobalHandles* global_handles = isolate->global_handles();
CHECK_EQ(0, global_handles->block_count());
CHECK_EQ(0, global_handles->global_handles_count());
Object* object = isolate->heap()->undefined_value();
const int kNumberOfBlocks = 5;
typedef Handle<Object> Block[kBlockSize];
for (int round = 0; round < 3; round++) {
Block blocks[kNumberOfBlocks];
for (int i = 0; i < kNumberOfBlocks; i++) {
for (int j = 0; j < kBlockSize; j++) {
blocks[i][j] = global_handles->Create(object);
}
}
CHECK_EQ(kNumberOfBlocks, global_handles->block_count());
for (int i = 0; i < kNumberOfBlocks; i++) {
for (int j = 0; j < kBlockSize; j++) {
global_handles->Destroy(blocks[i][j].location());
}
}
isolate->heap()->CollectAllAvailableGarbage("BlockCollection");
CHECK_EQ(0, global_handles->global_handles_count());
CHECK_EQ(1, global_handles->block_count());
}
}
class RandomMutationData {
public:
explicit RandomMutationData(Isolate* isolate)
: isolate_(isolate), weak_offset_(0) {}
void Mutate(double strong_growth_tendency,
double weak_growth_tendency = 0.05) {
for (int i = 0; i < kBlockSize * 100; i++) {
if (rng_.next(strong_growth_tendency)) {
AddStrong();
} else if (strong_nodes_.size() != 0) {
size_t to_remove = rng_.next(static_cast<int>(strong_nodes_.size()));
RemoveStrong(to_remove);
}
if (rng_.next(weak_growth_tendency)) AddWeak();
if (rng_.next(0.05)) {
#ifdef DEBUG
isolate_->global_handles()->VerifyBlockInvariants();
#endif
}
if (rng_.next(0.0001)) {
isolate_->heap()->PerformScavenge();
} else if (rng_.next(0.00003)) {
isolate_->heap()->CollectAllAvailableGarbage();
}
CheckSizes();
}
}
void RemoveAll() {
while (strong_nodes_.size() != 0) {
RemoveStrong(strong_nodes_.size() - 1);
}
isolate_->heap()->PerformScavenge();
isolate_->heap()->CollectAllAvailableGarbage();
CheckSizes();
}
private:
typedef std::vector<Object**> NodeVector;
typedef std::map<int32_t, Object**> NodeMap;
void CheckSizes() {
int stored_sizes =
static_cast<int>(strong_nodes_.size() + weak_nodes_.size());
CHECK_EQ(isolate_->global_handles()->global_handles_count(), stored_sizes);
}
void AddStrong() {
Object* object = isolate_->heap()->undefined_value();
Object** location = isolate_->global_handles()->Create(object).location();
strong_nodes_.push_back(location);
}
void RemoveStrong(size_t offset) {
isolate_->global_handles()->Destroy(strong_nodes_.at(offset));
strong_nodes_.erase(strong_nodes_.begin() + offset);
}
void AddWeak() {
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_);
v8::HandleScope scope(isolate);
v8::Local<v8::Object> object = v8::Object::New();
int32_t offset = ++weak_offset_;
object->Set(7, v8::Integer::New(offset, isolate));
v8::Persistent<v8::Object> persistent(isolate, object);
persistent.MakeWeak(isolate, this, WeakCallback);
persistent.MarkIndependent();
Object** location = v8::Utils::OpenPersistent(persistent).location();
bool inserted =
weak_nodes_.insert(std::make_pair(offset, location)).second;
CHECK(inserted);
}
static void WeakCallback(v8::Isolate* isolate,
v8::Persistent<v8::Object>* persistent,
RandomMutationData* data) {
v8::Local<v8::Object> object =
v8::Local<v8::Object>::New(isolate, *persistent);
int32_t offset =
v8::Local<v8::Integer>::Cast(object->Get(7))->Int32Value();
Object** location = v8::Utils::OpenPersistent(persistent).location();
NodeMap& weak_nodes = data->weak_nodes_;
NodeMap::iterator it = weak_nodes.find(offset);
CHECK(it != weak_nodes.end());
CHECK(it->second == location);
weak_nodes.erase(it);
persistent->Dispose();
}
Isolate* isolate_;
RandomNumberGenerator rng_;
NodeVector strong_nodes_;
NodeMap weak_nodes_;
int32_t weak_offset_;
};
TEST(RandomMutation) {
v8::V8::Initialize();
Isolate* isolate = Isolate::Current();
CHECK_EQ(0, isolate->global_handles()->block_count());
HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(
v8::Context::New(reinterpret_cast<v8::Isolate*>(isolate)));
RandomMutationData data(isolate);
// grow some
data.Mutate(0.65);
data.Mutate(0.55);
// balanced mutation
for (int i = 0; i < 3; i++) data.Mutate(0.50);
// shrink some
data.Mutate(0.45);
data.Mutate(0.35);
// clear everything
data.RemoveAll();
}
......@@ -40,58 +40,6 @@
#include "cctest.h"
#include "zone-inl.h"
// Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
class RandomNumberGenerator {
public:
RandomNumberGenerator() {
init();
}
void init(uint32_t seed = 0x5688c73e) {
static const uint32_t phi = 0x9e3779b9;
c = 362436;
i = kQSize-1;
Q[0] = seed;
Q[1] = seed + phi;
Q[2] = seed + phi + phi;
for (unsigned j = 3; j < kQSize; j++) {
Q[j] = Q[j - 3] ^ Q[j - 2] ^ phi ^ j;
}
}
uint32_t next() {
uint64_t a = 18782;
uint32_t r = 0xfffffffe;
i = (i + 1) & (kQSize-1);
uint64_t t = a * Q[i] + c;
c = (t >> 32);
uint32_t x = static_cast<uint32_t>(t + c);
if (x < c) {
x++;
c++;
}
return (Q[i] = r - x);
}
uint32_t next(int max) {
return next() % max;
}
bool next(double threshold) {
ASSERT(threshold >= 0.0 && threshold <= 1.0);
if (threshold == 1.0) return true;
if (threshold == 0.0) return false;
uint32_t value = next() % 100000;
return threshold > static_cast<double>(value)/100000.0;
}
private:
static const uint32_t kQSize = 4096;
uint32_t Q[kQSize];
uint32_t c;
uint32_t i;
};
using namespace v8::internal;
......
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