Revision: 23046
Author: [email protected]
Date: Mon Aug 11 14:22:24 2014 UTC
Log: Move store-buffer to heap and remove some unnecessary includes.
BUG=
[email protected]
Review URL: https://codereview.chromium.org/463523002
http://code.google.com/p/v8/source/detail?r=23046
Added:
/branches/bleeding_edge/src/heap/store-buffer-inl.h
/branches/bleeding_edge/src/heap/store-buffer.cc
/branches/bleeding_edge/src/heap/store-buffer.h
Deleted:
/branches/bleeding_edge/src/store-buffer-inl.h
/branches/bleeding_edge/src/store-buffer.cc
/branches/bleeding_edge/src/store-buffer.h
Modified:
/branches/bleeding_edge/BUILD.gn
/branches/bleeding_edge/src/assembler.cc
/branches/bleeding_edge/src/heap/heap-inl.h
/branches/bleeding_edge/src/heap/heap.cc
/branches/bleeding_edge/src/heap/heap.h
/branches/bleeding_edge/src/heap/spaces.h
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/v8.cc
/branches/bleeding_edge/tools/gyp/v8.gyp
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/heap/store-buffer-inl.h Mon Aug 11 14:22:24
2014 UTC
@@ -0,0 +1,63 @@
+// Copyright 2011 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_STORE_BUFFER_INL_H_
+#define V8_STORE_BUFFER_INL_H_
+
+#include "src/heap/store-buffer.h"
+
+namespace v8 {
+namespace internal {
+
+Address StoreBuffer::TopAddress() {
+ return reinterpret_cast<Address>(heap_->store_buffer_top_address());
+}
+
+
+void StoreBuffer::Mark(Address addr) {
+ DCHECK(!heap_->cell_space()->Contains(addr));
+ DCHECK(!heap_->code_space()->Contains(addr));
+ DCHECK(!heap_->old_data_space()->Contains(addr));
+ Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
+ *top++ = addr;
+ heap_->public_set_store_buffer_top(top);
+ if ((reinterpret_cast<uintptr_t>(top) & kStoreBufferOverflowBit) != 0) {
+ DCHECK(top == limit_);
+ Compact();
+ } else {
+ DCHECK(top < limit_);
+ }
+}
+
+
+void StoreBuffer::EnterDirectlyIntoStoreBuffer(Address addr) {
+ if (store_buffer_rebuilding_enabled_) {
+ SLOW_DCHECK(!heap_->cell_space()->Contains(addr) &&
+ !heap_->code_space()->Contains(addr) &&
+ !heap_->old_data_space()->Contains(addr) &&
+ !heap_->new_space()->Contains(addr));
+ Address* top = old_top_;
+ *top++ = addr;
+ old_top_ = top;
+ old_buffer_is_sorted_ = false;
+ old_buffer_is_filtered_ = false;
+ if (top >= old_limit_) {
+ DCHECK(callback_ != NULL);
+ (*callback_)(heap_, MemoryChunk::FromAnyPointerAddress(heap_, addr),
+ kStoreBufferFullEvent);
+ }
+ }
+}
+
+
+void StoreBuffer::ClearDeadObject(HeapObject* object) {
+ Address& map_field = Memory::Address_at(object->address());
+ if (heap_->map_space()->Contains(map_field)) {
+ map_field = NULL;
+ }
+}
+}
+} // namespace v8::internal
+
+#endif // V8_STORE_BUFFER_INL_H_
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/heap/store-buffer.cc Mon Aug 11 14:22:24
2014 UTC
@@ -0,0 +1,589 @@
+// Copyright 2011 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 <algorithm>
+
+#include "src/v8.h"
+
+#include "src/base/atomicops.h"
+#include "src/counters.h"
+#include "src/heap/store-buffer-inl.h"
+
+namespace v8 {
+namespace internal {
+
+StoreBuffer::StoreBuffer(Heap* heap)
+ : heap_(heap),
+ start_(NULL),
+ limit_(NULL),
+ old_start_(NULL),
+ old_limit_(NULL),
+ old_top_(NULL),
+ old_reserved_limit_(NULL),
+ old_buffer_is_sorted_(false),
+ old_buffer_is_filtered_(false),
+ during_gc_(false),
+ store_buffer_rebuilding_enabled_(false),
+ callback_(NULL),
+ may_move_store_buffer_entries_(true),
+ virtual_memory_(NULL),
+ hash_set_1_(NULL),
+ hash_set_2_(NULL),
+ hash_sets_are_empty_(true) {}
+
+
+void StoreBuffer::SetUp() {
+ virtual_memory_ = new base::VirtualMemory(kStoreBufferSize * 3);
+ uintptr_t start_as_int =
+ reinterpret_cast<uintptr_t>(virtual_memory_->address());
+ start_ =
+ reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize *
2));
+ limit_ = start_ + (kStoreBufferSize / kPointerSize);
+
+ old_virtual_memory_ =
+ new base::VirtualMemory(kOldStoreBufferLength * kPointerSize);
+ old_top_ = old_start_ =
+ reinterpret_cast<Address*>(old_virtual_memory_->address());
+ // Don't know the alignment requirements of the OS, but it is certainly
not
+ // less than 0xfff.
+ DCHECK((reinterpret_cast<uintptr_t>(old_start_) & 0xfff) == 0);
+ int initial_length =
+ static_cast<int>(base::OS::CommitPageSize() / kPointerSize);
+ DCHECK(initial_length > 0);
+ DCHECK(initial_length <= kOldStoreBufferLength);
+ old_limit_ = old_start_ + initial_length;
+ old_reserved_limit_ = old_start_ + kOldStoreBufferLength;
+
+ CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_start_),
+ (old_limit_ - old_start_) *
kPointerSize,
+ false));
+
+ DCHECK(reinterpret_cast<Address>(start_) >= virtual_memory_->address());
+ DCHECK(reinterpret_cast<Address>(limit_) >= virtual_memory_->address());
+ Address* vm_limit = reinterpret_cast<Address*>(
+ reinterpret_cast<char*>(virtual_memory_->address()) +
+ virtual_memory_->size());
+ DCHECK(start_ <= vm_limit);
+ DCHECK(limit_ <= vm_limit);
+ USE(vm_limit);
+ DCHECK((reinterpret_cast<uintptr_t>(limit_) &
kStoreBufferOverflowBit) != 0);
+ DCHECK((reinterpret_cast<uintptr_t>(limit_ - 1) &
kStoreBufferOverflowBit) ==
+ 0);
+
+ CHECK(virtual_memory_->Commit(reinterpret_cast<Address>(start_),
+ kStoreBufferSize,
+ false)); // Not executable.
+ heap_->public_set_store_buffer_top(start_);
+
+ hash_set_1_ = new uintptr_t[kHashSetLength];
+ hash_set_2_ = new uintptr_t[kHashSetLength];
+ hash_sets_are_empty_ = false;
+
+ ClearFilteringHashSets();
+}
+
+
+void StoreBuffer::TearDown() {
+ delete virtual_memory_;
+ delete old_virtual_memory_;
+ delete[] hash_set_1_;
+ delete[] hash_set_2_;
+ old_start_ = old_top_ = old_limit_ = old_reserved_limit_ = NULL;
+ start_ = limit_ = NULL;
+ heap_->public_set_store_buffer_top(start_);
+}
+
+
+void StoreBuffer::StoreBufferOverflow(Isolate* isolate) {
+ isolate->heap()->store_buffer()->Compact();
+ isolate->counters()->store_buffer_overflows()->Increment();
+}
+
+
+void StoreBuffer::Uniq() {
+ // Remove adjacent duplicates and cells that do not point at new space.
+ Address previous = NULL;
+ Address* write = old_start_;
+ DCHECK(may_move_store_buffer_entries_);
+ for (Address* read = old_start_; read < old_top_; read++) {
+ Address current = *read;
+ if (current != previous) {
+ if (heap_->InNewSpace(*reinterpret_cast<Object**>(current))) {
+ *write++ = current;
+ }
+ }
+ previous = current;
+ }
+ old_top_ = write;
+}
+
+
+bool StoreBuffer::SpaceAvailable(intptr_t space_needed) {
+ return old_limit_ - old_top_ >= space_needed;
+}
+
+
+void StoreBuffer::EnsureSpace(intptr_t space_needed) {
+ while (old_limit_ - old_top_ < space_needed &&
+ old_limit_ < old_reserved_limit_) {
+ size_t grow = old_limit_ - old_start_; // Double size.
+ CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_limit_),
+ grow * kPointerSize, false));
+ old_limit_ += grow;
+ }
+
+ if (SpaceAvailable(space_needed)) return;
+
+ if (old_buffer_is_filtered_) return;
+ DCHECK(may_move_store_buffer_entries_);
+ Compact();
+
+ old_buffer_is_filtered_ = true;
+ bool page_has_scan_on_scavenge_flag = false;
+
+ PointerChunkIterator it(heap_);
+ MemoryChunk* chunk;
+ while ((chunk = it.next()) != NULL) {
+ if (chunk->scan_on_scavenge()) {
+ page_has_scan_on_scavenge_flag = true;
+ break;
+ }
+ }
+
+ if (page_has_scan_on_scavenge_flag) {
+ Filter(MemoryChunk::SCAN_ON_SCAVENGE);
+ }
+
+ if (SpaceAvailable(space_needed)) return;
+
+ // Sample 1 entry in 97 and filter out the pages where we estimate that
more
+ // than 1 in 8 pointers are to new space.
+ static const int kSampleFinenesses = 5;
+ static const struct Samples {
+ int prime_sample_step;
+ int threshold;
+ } samples[kSampleFinenesses] = {
+ {97, ((Page::kPageSize / kPointerSize) / 97) / 8},
+ {23, ((Page::kPageSize / kPointerSize) / 23) / 16},
+ {7, ((Page::kPageSize / kPointerSize) / 7) / 32},
+ {3, ((Page::kPageSize / kPointerSize) / 3) / 256},
+ {1, 0}};
+ for (int i = 0; i < kSampleFinenesses; i++) {
+ ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold);
+ // As a last resort we mark all pages as being exempt from the store
buffer.
+ DCHECK(i != (kSampleFinenesses - 1) || old_top_ == old_start_);
+ if (SpaceAvailable(space_needed)) return;
+ }
+ UNREACHABLE();
+}
+
+
+// Sample the store buffer to see if some pages are taking up a lot of
space
+// in the store buffer.
+void StoreBuffer::ExemptPopularPages(int prime_sample_step, int threshold)
{
+ PointerChunkIterator it(heap_);
+ MemoryChunk* chunk;
+ while ((chunk = it.next()) != NULL) {
+ chunk->set_store_buffer_counter(0);
+ }
+ bool created_new_scan_on_scavenge_pages = false;
+ MemoryChunk* previous_chunk = NULL;
+ for (Address* p = old_start_; p < old_top_; p += prime_sample_step) {
+ Address addr = *p;
+ MemoryChunk* containing_chunk = NULL;
+ if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
+ containing_chunk = previous_chunk;
+ } else {
+ containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr);
+ }
+ int old_counter = containing_chunk->store_buffer_counter();
+ if (old_counter >= threshold) {
+ containing_chunk->set_scan_on_scavenge(true);
+ created_new_scan_on_scavenge_pages = true;
+ }
+ containing_chunk->set_store_buffer_counter(old_counter + 1);
+ previous_chunk = containing_chunk;
+ }
+ if (created_new_scan_on_scavenge_pages) {
+ Filter(MemoryChunk::SCAN_ON_SCAVENGE);
+ }
+ old_buffer_is_filtered_ = true;
+}
+
+
+void StoreBuffer::Filter(int flag) {
+ Address* new_top = old_start_;
+ MemoryChunk* previous_chunk = NULL;
+ for (Address* p = old_start_; p < old_top_; p++) {
+ Address addr = *p;
+ MemoryChunk* containing_chunk = NULL;
+ if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
+ containing_chunk = previous_chunk;
+ } else {
+ containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr);
+ previous_chunk = containing_chunk;
+ }
+ if (!containing_chunk->IsFlagSet(flag)) {
+ *new_top++ = addr;
+ }
+ }
+ old_top_ = new_top;
+
+ // Filtering hash sets are inconsistent with the store buffer after this
+ // operation.
+ ClearFilteringHashSets();
+}
+
+
+void StoreBuffer::SortUniq() {
+ Compact();
+ if (old_buffer_is_sorted_) return;
+ std::sort(old_start_, old_top_);
+ Uniq();
+
+ old_buffer_is_sorted_ = true;
+
+ // Filtering hash sets are inconsistent with the store buffer after this
+ // operation.
+ ClearFilteringHashSets();
+}
+
+
+bool StoreBuffer::PrepareForIteration() {
+ Compact();
+ PointerChunkIterator it(heap_);
+ MemoryChunk* chunk;
+ bool page_has_scan_on_scavenge_flag = false;
+ while ((chunk = it.next()) != NULL) {
+ if (chunk->scan_on_scavenge()) {
+ page_has_scan_on_scavenge_flag = true;
+ break;
+ }
+ }
+
+ if (page_has_scan_on_scavenge_flag) {
+ Filter(MemoryChunk::SCAN_ON_SCAVENGE);
+ }
+
+ // Filtering hash sets are inconsistent with the store buffer after
+ // iteration.
+ ClearFilteringHashSets();
+
+ return page_has_scan_on_scavenge_flag;
+}
+
+
+#ifdef DEBUG
+void StoreBuffer::Clean() {
+ ClearFilteringHashSets();
+ Uniq(); // Also removes things that no longer point to new space.
+ EnsureSpace(kStoreBufferSize / 2);
+}
+
+
+static Address* in_store_buffer_1_element_cache = NULL;
+
+
+bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) {
+ if (!FLAG_enable_slow_asserts) return true;
+ if (in_store_buffer_1_element_cache != NULL &&
+ *in_store_buffer_1_element_cache == cell_address) {
+ return true;
+ }
+ Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
+ for (Address* current = top - 1; current >= start_; current--) {
+ if (*current == cell_address) {
+ in_store_buffer_1_element_cache = current;
+ return true;
+ }
+ }
+ for (Address* current = old_top_ - 1; current >= old_start_; current--) {
+ if (*current == cell_address) {
+ in_store_buffer_1_element_cache = current;
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+
+void StoreBuffer::ClearFilteringHashSets() {
+ if (!hash_sets_are_empty_) {
+ memset(reinterpret_cast<void*>(hash_set_1_), 0,
+ sizeof(uintptr_t) * kHashSetLength);
+ memset(reinterpret_cast<void*>(hash_set_2_), 0,
+ sizeof(uintptr_t) * kHashSetLength);
+ hash_sets_are_empty_ = true;
+ }
+}
+
+
+void StoreBuffer::GCPrologue() {
+ ClearFilteringHashSets();
+ during_gc_ = true;
+}
+
+
+#ifdef VERIFY_HEAP
+void StoreBuffer::VerifyPointers(LargeObjectSpace* space) {
+ LargeObjectIterator it(space);
+ for (HeapObject* object = it.Next(); object != NULL; object = it.Next())
{
+ if (object->IsFixedArray()) {
+ Address slot_address = object->address();
+ Address end = object->address() + object->Size();
+
+ while (slot_address < end) {
+ HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address);
+ // When we are not in GC the Heap::InNewSpace() predicate
+ // checks that pointers which satisfy predicate point into
+ // the active semispace.
+ Object* object = reinterpret_cast<Object*>(
+
base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
+ heap_->InNewSpace(object);
+ slot_address += kPointerSize;
+ }
+ }
+ }
+}
+#endif
+
+
+void StoreBuffer::Verify() {
+#ifdef VERIFY_HEAP
+ VerifyPointers(heap_->lo_space());
+#endif
+}
+
+
+void StoreBuffer::GCEpilogue() {
+ during_gc_ = false;
+#ifdef VERIFY_HEAP
+ if (FLAG_verify_heap) {
+ Verify();
+ }
+#endif
+}
+
+
+void StoreBuffer::FindPointersToNewSpaceInRegion(
+ Address start, Address end, ObjectSlotCallback slot_callback,
+ bool clear_maps) {
+ for (Address slot_address = start; slot_address < end;
+ slot_address += kPointerSize) {
+ Object** slot = reinterpret_cast<Object**>(slot_address);
+ Object* object = reinterpret_cast<Object*>(
+ base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
+ if (heap_->InNewSpace(object)) {
+ HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
+ DCHECK(heap_object->IsHeapObject());
+ // The new space object was not promoted if it still contains a map
+ // pointer. Clear the map field now lazily.
+ if (clear_maps) ClearDeadObject(heap_object);
+ slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
+ object = reinterpret_cast<Object*>(
+ base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
+ if (heap_->InNewSpace(object)) {
+ EnterDirectlyIntoStoreBuffer(slot_address);
+ }
+ }
+ }
+}
+
+
+void StoreBuffer::IteratePointersInStoreBuffer(ObjectSlotCallback
slot_callback,
+ bool clear_maps) {
+ Address* limit = old_top_;
+ old_top_ = old_start_;
+ {
+ DontMoveStoreBufferEntriesScope scope(this);
+ for (Address* current = old_start_; current < limit; current++) {
+#ifdef DEBUG
+ Address* saved_top = old_top_;
+#endif
+ Object** slot = reinterpret_cast<Object**>(*current);
+ Object* object = reinterpret_cast<Object*>(
+ base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
+ if (heap_->InFromSpace(object)) {
+ HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
+ // The new space object was not promoted if it still contains a map
+ // pointer. Clear the map field now lazily.
+ if (clear_maps) ClearDeadObject(heap_object);
+ slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
+ object = reinterpret_cast<Object*>(
+
base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
+ if (heap_->InNewSpace(object)) {
+ EnterDirectlyIntoStoreBuffer(reinterpret_cast<Address>(slot));
+ }
+ }
+ DCHECK(old_top_ == saved_top + 1 || old_top_ == saved_top);
+ }
+ }
+}
+
+
+void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback
slot_callback) {
+ IteratePointersToNewSpace(slot_callback, false);
+}
+
+
+void StoreBuffer::IteratePointersToNewSpaceAndClearMaps(
+ ObjectSlotCallback slot_callback) {
+ IteratePointersToNewSpace(slot_callback, true);
+}
+
+
+void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback
slot_callback,
+ bool clear_maps) {
+ // We do not sort or remove duplicated entries from the store buffer
because
+ // we expect that callback will rebuild the store buffer thus removing
+ // all duplicates and pointers to old space.
+ bool some_pages_to_scan = PrepareForIteration();
+
+ // TODO(gc): we want to skip slots on evacuation candidates
+ // but we can't simply figure that out from slot address
+ // because slot can belong to a large object.
+ IteratePointersInStoreBuffer(slot_callback, clear_maps);
+
+ // We are done scanning all the pointers that were in the store buffer,
but
+ // there may be some pages marked scan_on_scavenge that have pointers to
new
+ // space that are not in the store buffer. We must scan them now. As we
+ // scan, the surviving pointers to new space will be added to the store
+ // buffer. If there are still a lot of pointers to new space then we
will
+ // keep the scan_on_scavenge flag on the page and discard the pointers
that
+ // were added to the store buffer. If there are not many pointers to new
+ // space left on the page we will keep the pointers in the store buffer
and
+ // remove the flag from the page.
+ if (some_pages_to_scan) {
+ if (callback_ != NULL) {
+ (*callback_)(heap_, NULL, kStoreBufferStartScanningPagesEvent);
+ }
+ PointerChunkIterator it(heap_);
+ MemoryChunk* chunk;
+ while ((chunk = it.next()) != NULL) {
+ if (chunk->scan_on_scavenge()) {
+ chunk->set_scan_on_scavenge(false);
+ if (callback_ != NULL) {
+ (*callback_)(heap_, chunk, kStoreBufferScanningPageEvent);
+ }
+ if (chunk->owner() == heap_->lo_space()) {
+ LargePage* large_page = reinterpret_cast<LargePage*>(chunk);
+ HeapObject* array = large_page->GetObject();
+ DCHECK(array->IsFixedArray());
+ Address start = array->address();
+ Address end = start + array->Size();
+ FindPointersToNewSpaceInRegion(start, end, slot_callback,
clear_maps);
+ } else {
+ Page* page = reinterpret_cast<Page*>(chunk);
+ PagedSpace* owner = reinterpret_cast<PagedSpace*>(page->owner());
+ Address start = page->area_start();
+ Address end = page->area_end();
+ if (owner == heap_->map_space()) {
+ DCHECK(page->WasSweptPrecisely());
+ HeapObjectIterator iterator(page, NULL);
+ for (HeapObject* heap_object = iterator.Next(); heap_object !=
NULL;
+ heap_object = iterator.Next()) {
+ // We skip free space objects.
+ if (!heap_object->IsFiller()) {
+ FindPointersToNewSpaceInRegion(
+ heap_object->address() + HeapObject::kHeaderSize,
+ heap_object->address() + heap_object->Size(),
slot_callback,
+ clear_maps);
+ }
+ }
+ } else {
+ if (!page->SweepingCompleted()) {
+ heap_->mark_compact_collector()->SweepInParallel(page,
owner);
+ if (!page->SweepingCompleted()) {
+ // We were not able to sweep that page, i.e., a concurrent
+ // sweeper thread currently owns this page.
+ // TODO(hpayer): This may introduce a huge pause here. We
+ // just care about finish sweeping of the scan on scavenge
page.
+ heap_->mark_compact_collector()->EnsureSweepingCompleted();
+ }
+ }
+ // TODO(hpayer): remove the special casing and merge map and
pointer
+ // space handling as soon as we removed conservative sweeping.
+ CHECK(page->owner() == heap_->old_pointer_space());
+ if (heap_->old_pointer_space()->swept_precisely()) {
+ HeapObjectIterator iterator(page, NULL);
+ for (HeapObject* heap_object = iterator.Next();
+ heap_object != NULL; heap_object = iterator.Next()) {
+ // We iterate over objects that contain new space pointers
only.
+ if (heap_object->MayContainNewSpacePointers()) {
+ FindPointersToNewSpaceInRegion(
+ heap_object->address() + HeapObject::kHeaderSize,
+ heap_object->address() + heap_object->Size(),
+ slot_callback, clear_maps);
+ }
+ }
+ } else {
+ FindPointersToNewSpaceInRegion(start, end, slot_callback,
+ clear_maps);
+ }
+ }
+ }
+ }
+ }
+ if (callback_ != NULL) {
+ (*callback_)(heap_, NULL, kStoreBufferScanningPageEvent);
+ }
+ }
+}
+
+
+void StoreBuffer::Compact() {
+ Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
+
+ if (top == start_) return;
+
+ // There's no check of the limit in the loop below so we check here for
+ // the worst case (compaction doesn't eliminate any pointers).
+ DCHECK(top <= limit_);
+ heap_->public_set_store_buffer_top(start_);
+ EnsureSpace(top - start_);
+ DCHECK(may_move_store_buffer_entries_);
+ // Goes through the addresses in the store buffer attempting to remove
+ // duplicates. In the interest of speed this is a lossy operation. Some
+ // duplicates will remain. We have two hash sets with different hash
+ // functions to reduce the number of unnecessary clashes.
+ hash_sets_are_empty_ = false; // Hash sets are in use.
+ for (Address* current = start_; current < top; current++) {
+ DCHECK(!heap_->cell_space()->Contains(*current));
+ DCHECK(!heap_->code_space()->Contains(*current));
+ DCHECK(!heap_->old_data_space()->Contains(*current));
+ uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current);
+ // Shift out the last bits including any tags.
+ int_addr >>= kPointerSizeLog2;
+ // The upper part of an address is basically random because of ASLR
and OS
+ // non-determinism, so we use only the bits within a page for hashing
to
+ // make v8's behavior (more) deterministic.
+ uintptr_t hash_addr =
+ int_addr & (Page::kPageAlignmentMask >> kPointerSizeLog2);
+ int hash1 = ((hash_addr ^ (hash_addr >> kHashSetLengthLog2)) &
+ (kHashSetLength - 1));
+ if (hash_set_1_[hash1] == int_addr) continue;
+ uintptr_t hash2 = (hash_addr - (hash_addr >> kHashSetLengthLog2));
+ hash2 ^= hash2 >> (kHashSetLengthLog2 * 2);
+ hash2 &= (kHashSetLength - 1);
+ if (hash_set_2_[hash2] == int_addr) continue;
+ if (hash_set_1_[hash1] == 0) {
+ hash_set_1_[hash1] = int_addr;
+ } else if (hash_set_2_[hash2] == 0) {
+ hash_set_2_[hash2] = int_addr;
+ } else {
+ // Rather than slowing down we just throw away some entries. This
will
+ // cause some duplicates to remain undetected.
+ hash_set_1_[hash1] = int_addr;
+ hash_set_2_[hash2] = 0;
+ }
+ old_buffer_is_sorted_ = false;
+ old_buffer_is_filtered_ = false;
+ *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2);
+ DCHECK(old_top_ <= old_limit_);
+ }
+ heap_->isolate()->counters()->store_buffer_compactions()->Increment();
+}
+}
+} // namespace v8::internal
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/heap/store-buffer.h Mon Aug 11 14:22:24
2014 UTC
@@ -0,0 +1,221 @@
+// Copyright 2011 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_STORE_BUFFER_H_
+#define V8_STORE_BUFFER_H_
+
+#include "src/allocation.h"
+#include "src/base/logging.h"
+#include "src/base/platform/platform.h"
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+class Page;
+class PagedSpace;
+class StoreBuffer;
+
+typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to);
+
+typedef void (StoreBuffer::*RegionCallback)(Address start, Address end,
+ ObjectSlotCallback
slot_callback,
+ bool clear_maps);
+
+// Used to implement the write barrier by collecting addresses of pointers
+// between spaces.
+class StoreBuffer {
+ public:
+ explicit StoreBuffer(Heap* heap);
+
+ static void StoreBufferOverflow(Isolate* isolate);
+
+ inline Address TopAddress();
+
+ void SetUp();
+ void TearDown();
+
+ // This is used by the mutator to enter addresses into the store buffer.
+ inline void Mark(Address addr);
+
+ // This is used by the heap traversal to enter the addresses into the
store
+ // buffer that should still be in the store buffer after GC. It enters
+ // addresses directly into the old buffer because the GC starts by
wiping the
+ // old buffer and thereafter only visits each cell once so there is no
need
+ // to attempt to remove any dupes. During the first part of a GC we
+ // are using the store buffer to access the old spaces and at the same
time
+ // we are rebuilding the store buffer using this function. There is,
however
+ // no issue of overwriting the buffer we are iterating over, because this
+ // stage of the scavenge can only reduce the number of addresses in the
store
+ // buffer (some objects are promoted so pointers to them do not need to
be in
+ // the store buffer). The later parts of the GC scan the pages that are
+ // exempt from the store buffer and process the promotion queue. These
steps
+ // can overflow this buffer. We check for this and on overflow we call
the
+ // callback set up with the StoreBufferRebuildScope object.
+ inline void EnterDirectlyIntoStoreBuffer(Address addr);
+
+ // Iterates over all pointers that go from old space to new space. It
will
+ // delete the store buffer as it starts so the callback should reenter
+ // surviving old-to-new pointers into the store buffer to rebuild it.
+ void IteratePointersToNewSpace(ObjectSlotCallback callback);
+
+ // Same as IteratePointersToNewSpace but additonally clears maps in
objects
+ // referenced from the store buffer that do not contain a forwarding
pointer.
+ void IteratePointersToNewSpaceAndClearMaps(ObjectSlotCallback callback);
+
+ static const int kStoreBufferOverflowBit = 1 << (14 + kPointerSizeLog2);
+ static const int kStoreBufferSize = kStoreBufferOverflowBit;
+ static const int kStoreBufferLength = kStoreBufferSize / sizeof(Address);
+ static const int kOldStoreBufferLength = kStoreBufferLength * 16;
+ static const int kHashSetLengthLog2 = 12;
+ static const int kHashSetLength = 1 << kHashSetLengthLog2;
+
+ void Compact();
+
+ void GCPrologue();
+ void GCEpilogue();
+
+ Object*** Limit() { return reinterpret_cast<Object***>(old_limit_); }
+ Object*** Start() { return reinterpret_cast<Object***>(old_start_); }
+ Object*** Top() { return reinterpret_cast<Object***>(old_top_); }
+ void SetTop(Object*** top) {
+ DCHECK(top >= Start());
+ DCHECK(top <= Limit());
+ old_top_ = reinterpret_cast<Address*>(top);
+ }
+
+ bool old_buffer_is_sorted() { return old_buffer_is_sorted_; }
+ bool old_buffer_is_filtered() { return old_buffer_is_filtered_; }
+
+ // Goes through the store buffer removing pointers to things that have
+ // been promoted. Rebuilds the store buffer completely if it overflowed.
+ void SortUniq();
+
+ void EnsureSpace(intptr_t space_needed);
+ void Verify();
+
+ bool PrepareForIteration();
+
+#ifdef DEBUG
+ void Clean();
+ // Slow, for asserts only.
+ bool CellIsInStoreBuffer(Address cell);
+#endif
+
+ void Filter(int flag);
+
+ private:
+ Heap* heap_;
+
+ // The store buffer is divided up into a new buffer that is constantly
being
+ // filled by mutator activity and an old buffer that is filled with the
data
+ // from the new buffer after compression.
+ Address* start_;
+ Address* limit_;
+
+ Address* old_start_;
+ Address* old_limit_;
+ Address* old_top_;
+ Address* old_reserved_limit_;
+ base::VirtualMemory* old_virtual_memory_;
+
+ bool old_buffer_is_sorted_;
+ bool old_buffer_is_filtered_;
+ bool during_gc_;
+ // The garbage collector iterates over many pointers to new space that
are not
+ // handled by the store buffer. This flag indicates whether the pointers
+ // found by the callbacks should be added to the store buffer or not.
+ bool store_buffer_rebuilding_enabled_;
+ StoreBufferCallback callback_;
+ bool may_move_store_buffer_entries_;
+
+ base::VirtualMemory* virtual_memory_;
+
+ // Two hash sets used for filtering.
+ // If address is in the hash set then it is guaranteed to be in the
+ // old part of the store buffer.
+ uintptr_t* hash_set_1_;
+ uintptr_t* hash_set_2_;
+ bool hash_sets_are_empty_;
+
+ void ClearFilteringHashSets();
+
+ bool SpaceAvailable(intptr_t space_needed);
+ void Uniq();
+ void ExemptPopularPages(int prime_sample_step, int threshold);
+
+ // Set the map field of the object to NULL if contains a map.
+ inline void ClearDeadObject(HeapObject* object);
+
+ void IteratePointersToNewSpace(ObjectSlotCallback callback, bool
clear_maps);
+
+ void FindPointersToNewSpaceInRegion(Address start, Address end,
+ ObjectSlotCallback slot_callback,
+ bool clear_maps);
+
+ // For each region of pointers on a page in use from an old space call
+ // visit_pointer_region callback.
+ // If either visit_pointer_region or callback can cause an allocation
+ // in old space and changes in allocation watermark then
+ // can_preallocate_during_iteration should be set to true.
+ void IteratePointersOnPage(PagedSpace* space, Page* page,
+ RegionCallback region_callback,
+ ObjectSlotCallback slot_callback);
+
+ void IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback,
+ bool clear_maps);
+
+#ifdef VERIFY_HEAP
+ void VerifyPointers(LargeObjectSpace* space);
+#endif
+
+ friend class StoreBufferRebuildScope;
+ friend class DontMoveStoreBufferEntriesScope;
+};
+
+
+class StoreBufferRebuildScope {
+ public:
+ explicit StoreBufferRebuildScope(Heap* heap, StoreBuffer* store_buffer,
+ StoreBufferCallback callback)
+ : store_buffer_(store_buffer),
+ stored_state_(store_buffer->store_buffer_rebuilding_enabled_),
+ stored_callback_(store_buffer->callback_) {
+ store_buffer_->store_buffer_rebuilding_enabled_ = true;
+ store_buffer_->callback_ = callback;
+ (*callback)(heap, NULL, kStoreBufferStartScanningPagesEvent);
+ }
+
+ ~StoreBufferRebuildScope() {
+ store_buffer_->callback_ = stored_callback_;
+ store_buffer_->store_buffer_rebuilding_enabled_ = stored_state_;
+ }
+
+ private:
+ StoreBuffer* store_buffer_;
+ bool stored_state_;
+ StoreBufferCallback stored_callback_;
+};
+
+
+class DontMoveStoreBufferEntriesScope {
+ public:
+ explicit DontMoveStoreBufferEntriesScope(StoreBuffer* store_buffer)
+ : store_buffer_(store_buffer),
+ stored_state_(store_buffer->may_move_store_buffer_entries_) {
+ store_buffer_->may_move_store_buffer_entries_ = false;
+ }
+
+ ~DontMoveStoreBufferEntriesScope() {
+ store_buffer_->may_move_store_buffer_entries_ = stored_state_;
+ }
+
+ private:
+ StoreBuffer* store_buffer_;
+ bool stored_state_;
+};
+}
+} // namespace v8::internal
+
+#endif // V8_STORE_BUFFER_H_
=======================================
--- /branches/bleeding_edge/src/store-buffer-inl.h Mon Aug 4 11:34:54 2014
UTC
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2011 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_STORE_BUFFER_INL_H_
-#define V8_STORE_BUFFER_INL_H_
-
-#include "src/store-buffer.h"
-
-namespace v8 {
-namespace internal {
-
-Address StoreBuffer::TopAddress() {
- return reinterpret_cast<Address>(heap_->store_buffer_top_address());
-}
-
-
-void StoreBuffer::Mark(Address addr) {
- DCHECK(!heap_->cell_space()->Contains(addr));
- DCHECK(!heap_->code_space()->Contains(addr));
- DCHECK(!heap_->old_data_space()->Contains(addr));
- Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
- *top++ = addr;
- heap_->public_set_store_buffer_top(top);
- if ((reinterpret_cast<uintptr_t>(top) & kStoreBufferOverflowBit) != 0) {
- DCHECK(top == limit_);
- Compact();
- } else {
- DCHECK(top < limit_);
- }
-}
-
-
-void StoreBuffer::EnterDirectlyIntoStoreBuffer(Address addr) {
- if (store_buffer_rebuilding_enabled_) {
- SLOW_DCHECK(!heap_->cell_space()->Contains(addr) &&
- !heap_->code_space()->Contains(addr) &&
- !heap_->old_data_space()->Contains(addr) &&
- !heap_->new_space()->Contains(addr));
- Address* top = old_top_;
- *top++ = addr;
- old_top_ = top;
- old_buffer_is_sorted_ = false;
- old_buffer_is_filtered_ = false;
- if (top >= old_limit_) {
- DCHECK(callback_ != NULL);
- (*callback_)(heap_,
- MemoryChunk::FromAnyPointerAddress(heap_, addr),
- kStoreBufferFullEvent);
- }
- }
-}
-
-
-void StoreBuffer::ClearDeadObject(HeapObject* object) {
- Address& map_field = Memory::Address_at(object->address());
- if (heap_->map_space()->Contains(map_field)) {
- map_field = NULL;
- }
-}
-
-
-} } // namespace v8::internal
-
-#endif // V8_STORE_BUFFER_INL_H_
=======================================
--- /branches/bleeding_edge/src/store-buffer.cc Mon Aug 4 11:34:54 2014 UTC
+++ /dev/null
@@ -1,601 +0,0 @@
-// Copyright 2011 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/store-buffer.h"
-
-#include <algorithm>
-
-#include "src/v8.h"
-
-#include "src/base/atomicops.h"
-#include "src/counters.h"
-#include "src/store-buffer-inl.h"
-
-namespace v8 {
-namespace internal {
-
-StoreBuffer::StoreBuffer(Heap* heap)
- : heap_(heap),
- start_(NULL),
- limit_(NULL),
- old_start_(NULL),
- old_limit_(NULL),
- old_top_(NULL),
- old_reserved_limit_(NULL),
- old_buffer_is_sorted_(false),
- old_buffer_is_filtered_(false),
- during_gc_(false),
- store_buffer_rebuilding_enabled_(false),
- callback_(NULL),
- may_move_store_buffer_entries_(true),
- virtual_memory_(NULL),
- hash_set_1_(NULL),
- hash_set_2_(NULL),
- hash_sets_are_empty_(true) {
-}
-
-
-void StoreBuffer::SetUp() {
- virtual_memory_ = new base::VirtualMemory(kStoreBufferSize * 3);
- uintptr_t start_as_int =
- reinterpret_cast<uintptr_t>(virtual_memory_->address());
- start_ =
- reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize *
2));
- limit_ = start_ + (kStoreBufferSize / kPointerSize);
-
- old_virtual_memory_ =
- new base::VirtualMemory(kOldStoreBufferLength * kPointerSize);
- old_top_ = old_start_ =
- reinterpret_cast<Address*>(old_virtual_memory_->address());
- // Don't know the alignment requirements of the OS, but it is certainly
not
- // less than 0xfff.
- DCHECK((reinterpret_cast<uintptr_t>(old_start_) & 0xfff) == 0);
- int initial_length =
- static_cast<int>(base::OS::CommitPageSize() / kPointerSize);
- DCHECK(initial_length > 0);
- DCHECK(initial_length <= kOldStoreBufferLength);
- old_limit_ = old_start_ + initial_length;
- old_reserved_limit_ = old_start_ + kOldStoreBufferLength;
-
- CHECK(old_virtual_memory_->Commit(
- reinterpret_cast<void*>(old_start_),
- (old_limit_ - old_start_) * kPointerSize,
- false));
-
- DCHECK(reinterpret_cast<Address>(start_) >= virtual_memory_->address());
- DCHECK(reinterpret_cast<Address>(limit_) >= virtual_memory_->address());
- Address* vm_limit = reinterpret_cast<Address*>(
- reinterpret_cast<char*>(virtual_memory_->address()) +
- virtual_memory_->size());
- DCHECK(start_ <= vm_limit);
- DCHECK(limit_ <= vm_limit);
- USE(vm_limit);
- DCHECK((reinterpret_cast<uintptr_t>(limit_) &
kStoreBufferOverflowBit) != 0);
- DCHECK((reinterpret_cast<uintptr_t>(limit_ - 1) &
kStoreBufferOverflowBit) ==
- 0);
-
- CHECK(virtual_memory_->Commit(reinterpret_cast<Address>(start_),
- kStoreBufferSize,
- false)); // Not executable.
- heap_->public_set_store_buffer_top(start_);
-
- hash_set_1_ = new uintptr_t[kHashSetLength];
- hash_set_2_ = new uintptr_t[kHashSetLength];
- hash_sets_are_empty_ = false;
-
- ClearFilteringHashSets();
-}
-
-
-void StoreBuffer::TearDown() {
- delete virtual_memory_;
- delete old_virtual_memory_;
- delete[] hash_set_1_;
- delete[] hash_set_2_;
- old_start_ = old_top_ = old_limit_ = old_reserved_limit_ = NULL;
- start_ = limit_ = NULL;
- heap_->public_set_store_buffer_top(start_);
-}
-
-
-void StoreBuffer::StoreBufferOverflow(Isolate* isolate) {
- isolate->heap()->store_buffer()->Compact();
- isolate->counters()->store_buffer_overflows()->Increment();
-}
-
-
-void StoreBuffer::Uniq() {
- // Remove adjacent duplicates and cells that do not point at new space.
- Address previous = NULL;
- Address* write = old_start_;
- DCHECK(may_move_store_buffer_entries_);
- for (Address* read = old_start_; read < old_top_; read++) {
- Address current = *read;
- if (current != previous) {
- if (heap_->InNewSpace(*reinterpret_cast<Object**>(current))) {
- *write++ = current;
- }
- }
- previous = current;
- }
- old_top_ = write;
-}
-
-
-bool StoreBuffer::SpaceAvailable(intptr_t space_needed) {
- return old_limit_ - old_top_ >= space_needed;
-}
-
-
-void StoreBuffer::EnsureSpace(intptr_t space_needed) {
- while (old_limit_ - old_top_ < space_needed &&
- old_limit_ < old_reserved_limit_) {
- size_t grow = old_limit_ - old_start_; // Double size.
- CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_limit_),
- grow * kPointerSize,
- false));
- old_limit_ += grow;
- }
-
- if (SpaceAvailable(space_needed)) return;
-
- if (old_buffer_is_filtered_) return;
- DCHECK(may_move_store_buffer_entries_);
- Compact();
-
- old_buffer_is_filtered_ = true;
- bool page_has_scan_on_scavenge_flag = false;
-
- PointerChunkIterator it(heap_);
- MemoryChunk* chunk;
- while ((chunk = it.next()) != NULL) {
- if (chunk->scan_on_scavenge()) {
- page_has_scan_on_scavenge_flag = true;
- break;
- }
- }
-
- if (page_has_scan_on_scavenge_flag) {
- Filter(MemoryChunk::SCAN_ON_SCAVENGE);
- }
-
- if (SpaceAvailable(space_needed)) return;
-
- // Sample 1 entry in 97 and filter out the pages where we estimate that
more
- // than 1 in 8 pointers are to new space.
- static const int kSampleFinenesses = 5;
- static const struct Samples {
- int prime_sample_step;
- int threshold;
- } samples[kSampleFinenesses] = {
- { 97, ((Page::kPageSize / kPointerSize) / 97) / 8 },
- { 23, ((Page::kPageSize / kPointerSize) / 23) / 16 },
- { 7, ((Page::kPageSize / kPointerSize) / 7) / 32 },
- { 3, ((Page::kPageSize / kPointerSize) / 3) / 256 },
- { 1, 0}
- };
- for (int i = 0; i < kSampleFinenesses; i++) {
- ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold);
- // As a last resort we mark all pages as being exempt from the store
buffer.
- DCHECK(i != (kSampleFinenesses - 1) || old_top_ == old_start_);
- if (SpaceAvailable(space_needed)) return;
- }
- UNREACHABLE();
-}
-
-
-// Sample the store buffer to see if some pages are taking up a lot of
space
-// in the store buffer.
-void StoreBuffer::ExemptPopularPages(int prime_sample_step, int threshold)
{
- PointerChunkIterator it(heap_);
- MemoryChunk* chunk;
- while ((chunk = it.next()) != NULL) {
- chunk->set_store_buffer_counter(0);
- }
- bool created_new_scan_on_scavenge_pages = false;
- MemoryChunk* previous_chunk = NULL;
- for (Address* p = old_start_; p < old_top_; p += prime_sample_step) {
- Address addr = *p;
- MemoryChunk* containing_chunk = NULL;
- if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
- containing_chunk = previous_chunk;
- } else {
- containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr);
- }
- int old_counter = containing_chunk->store_buffer_counter();
- if (old_counter >= threshold) {
- containing_chunk->set_scan_on_scavenge(true);
- created_new_scan_on_scavenge_pages = true;
- }
- containing_chunk->set_store_buffer_counter(old_counter + 1);
- previous_chunk = containing_chunk;
- }
- if (created_new_scan_on_scavenge_pages) {
- Filter(MemoryChunk::SCAN_ON_SCAVENGE);
- }
- old_buffer_is_filtered_ = true;
-}
-
-
-void StoreBuffer::Filter(int flag) {
- Address* new_top = old_start_;
- MemoryChunk* previous_chunk = NULL;
- for (Address* p = old_start_; p < old_top_; p++) {
- Address addr = *p;
- MemoryChunk* containing_chunk = NULL;
- if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
- containing_chunk = previous_chunk;
- } else {
- containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr);
- previous_chunk = containing_chunk;
- }
- if (!containing_chunk->IsFlagSet(flag)) {
- *new_top++ = addr;
- }
- }
- old_top_ = new_top;
-
- // Filtering hash sets are inconsistent with the store buffer after this
- // operation.
- ClearFilteringHashSets();
-}
-
-
-void StoreBuffer::SortUniq() {
- Compact();
- if (old_buffer_is_sorted_) return;
- std::sort(old_start_, old_top_);
- Uniq();
-
- old_buffer_is_sorted_ = true;
-
- // Filtering hash sets are inconsistent with the store buffer after this
- // operation.
- ClearFilteringHashSets();
-}
-
-
-bool StoreBuffer::PrepareForIteration() {
- Compact();
- PointerChunkIterator it(heap_);
- MemoryChunk* chunk;
- bool page_has_scan_on_scavenge_flag = false;
- while ((chunk = it.next()) != NULL) {
- if (chunk->scan_on_scavenge()) {
- page_has_scan_on_scavenge_flag = true;
- break;
- }
- }
-
- if (page_has_scan_on_scavenge_flag) {
- Filter(MemoryChunk::SCAN_ON_SCAVENGE);
- }
-
- // Filtering hash sets are inconsistent with the store buffer after
- // iteration.
- ClearFilteringHashSets();
-
- return page_has_scan_on_scavenge_flag;
-}
-
-
-#ifdef DEBUG
-void StoreBuffer::Clean() {
- ClearFilteringHashSets();
- Uniq(); // Also removes things that no longer point to new space.
- EnsureSpace(kStoreBufferSize / 2);
-}
-
-
-static Address* in_store_buffer_1_element_cache = NULL;
-
-
-bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) {
- if (!FLAG_enable_slow_asserts) return true;
- if (in_store_buffer_1_element_cache != NULL &&
- *in_store_buffer_1_element_cache == cell_address) {
- return true;
- }
- Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
- for (Address* current = top - 1; current >= start_; current--) {
- if (*current == cell_address) {
- in_store_buffer_1_element_cache = current;
- return true;
- }
- }
- for (Address* current = old_top_ - 1; current >= old_start_; current--) {
- if (*current == cell_address) {
- in_store_buffer_1_element_cache = current;
- return true;
- }
- }
- return false;
-}
-#endif
-
-
-void StoreBuffer::ClearFilteringHashSets() {
- if (!hash_sets_are_empty_) {
- memset(reinterpret_cast<void*>(hash_set_1_),
- 0,
- sizeof(uintptr_t) * kHashSetLength);
- memset(reinterpret_cast<void*>(hash_set_2_),
- 0,
- sizeof(uintptr_t) * kHashSetLength);
- hash_sets_are_empty_ = true;
- }
-}
-
-
-void StoreBuffer::GCPrologue() {
- ClearFilteringHashSets();
- during_gc_ = true;
-}
-
-
-#ifdef VERIFY_HEAP
-void StoreBuffer::VerifyPointers(LargeObjectSpace* space) {
- LargeObjectIterator it(space);
- for (HeapObject* object = it.Next(); object != NULL; object = it.Next())
{
- if (object->IsFixedArray()) {
- Address slot_address = object->address();
- Address end = object->address() + object->Size();
-
- while (slot_address < end) {
- HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address);
- // When we are not in GC the Heap::InNewSpace() predicate
- // checks that pointers which satisfy predicate point into
- // the active semispace.
- Object* object = reinterpret_cast<Object*>(
-
base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
- heap_->InNewSpace(object);
- slot_address += kPointerSize;
- }
- }
- }
-}
-#endif
-
-
-void StoreBuffer::Verify() {
-#ifdef VERIFY_HEAP
- VerifyPointers(heap_->lo_space());
-#endif
-}
-
-
-void StoreBuffer::GCEpilogue() {
- during_gc_ = false;
-#ifdef VERIFY_HEAP
- if (FLAG_verify_heap) {
- Verify();
- }
-#endif
-}
-
-
-void StoreBuffer::FindPointersToNewSpaceInRegion(
- Address start,
- Address end,
- ObjectSlotCallback slot_callback,
- bool clear_maps) {
- for (Address slot_address = start;
- slot_address < end;
- slot_address += kPointerSize) {
- Object** slot = reinterpret_cast<Object**>(slot_address);
- Object* object = reinterpret_cast<Object*>(
- base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
- if (heap_->InNewSpace(object)) {
- HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
- DCHECK(heap_object->IsHeapObject());
- // The new space object was not promoted if it still contains a map
- // pointer. Clear the map field now lazily.
- if (clear_maps) ClearDeadObject(heap_object);
- slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
- object = reinterpret_cast<Object*>(
- base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
- if (heap_->InNewSpace(object)) {
- EnterDirectlyIntoStoreBuffer(slot_address);
- }
- }
- }
-}
-
-
-void StoreBuffer::IteratePointersInStoreBuffer(
- ObjectSlotCallback slot_callback,
- bool clear_maps) {
- Address* limit = old_top_;
- old_top_ = old_start_;
- {
- DontMoveStoreBufferEntriesScope scope(this);
- for (Address* current = old_start_; current < limit; current++) {
-#ifdef DEBUG
- Address* saved_top = old_top_;
-#endif
- Object** slot = reinterpret_cast<Object**>(*current);
- Object* object = reinterpret_cast<Object*>(
- base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
- if (heap_->InFromSpace(object)) {
- HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
- // The new space object was not promoted if it still contains a map
- // pointer. Clear the map field now lazily.
- if (clear_maps) ClearDeadObject(heap_object);
- slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
- object = reinterpret_cast<Object*>(
-
base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
- if (heap_->InNewSpace(object)) {
- EnterDirectlyIntoStoreBuffer(reinterpret_cast<Address>(slot));
- }
- }
- DCHECK(old_top_ == saved_top + 1 || old_top_ == saved_top);
- }
- }
-}
-
-
-void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback
slot_callback) {
- IteratePointersToNewSpace(slot_callback, false);
-}
-
-
-void StoreBuffer::IteratePointersToNewSpaceAndClearMaps(
- ObjectSlotCallback slot_callback) {
- IteratePointersToNewSpace(slot_callback, true);
-}
-
-
-void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback
slot_callback,
- bool clear_maps) {
- // We do not sort or remove duplicated entries from the store buffer
because
- // we expect that callback will rebuild the store buffer thus removing
- // all duplicates and pointers to old space.
- bool some_pages_to_scan = PrepareForIteration();
-
- // TODO(gc): we want to skip slots on evacuation candidates
- // but we can't simply figure that out from slot address
- // because slot can belong to a large object.
- IteratePointersInStoreBuffer(slot_callback, clear_maps);
-
- // We are done scanning all the pointers that were in the store buffer,
but
- // there may be some pages marked scan_on_scavenge that have pointers to
new
- // space that are not in the store buffer. We must scan them now. As we
- // scan, the surviving pointers to new space will be added to the store
- // buffer. If there are still a lot of pointers to new space then we
will
- // keep the scan_on_scavenge flag on the page and discard the pointers
that
- // were added to the store buffer. If there are not many pointers to new
- // space left on the page we will keep the pointers in the store buffer
and
- // remove the flag from the page.
- if (some_pages_to_scan) {
- if (callback_ != NULL) {
- (*callback_)(heap_, NULL, kStoreBufferStartScanningPagesEvent);
- }
- PointerChunkIterator it(heap_);
- MemoryChunk* chunk;
- while ((chunk = it.next()) != NULL) {
- if (chunk->scan_on_scavenge()) {
- chunk->set_scan_on_scavenge(false);
- if (callback_ != NULL) {
- (*callback_)(heap_, chunk, kStoreBufferScanningPageEvent);
- }
- if (chunk->owner() == heap_->lo_space()) {
- LargePage* large_page = reinterpret_cast<LargePage*>(chunk);
- HeapObject* array = large_page->GetObject();
- DCHECK(array->IsFixedArray());
- Address start = array->address();
- Address end = start + array->Size();
- FindPointersToNewSpaceInRegion(start, end, slot_callback,
clear_maps);
- } else {
- Page* page = reinterpret_cast<Page*>(chunk);
- PagedSpace* owner = reinterpret_cast<PagedSpace*>(page->owner());
- Address start = page->area_start();
- Address end = page->area_end();
- if (owner == heap_->map_space()) {
- DCHECK(page->WasSweptPrecisely());
- HeapObjectIterator iterator(page, NULL);
- for (HeapObject* heap_object = iterator.Next(); heap_object !=
NULL;
- heap_object = iterator.Next()) {
- // We skip free space objects.
- if (!heap_object->IsFiller()) {
- FindPointersToNewSpaceInRegion(
- heap_object->address() + HeapObject::kHeaderSize,
- heap_object->address() + heap_object->Size(),
slot_callback,
- clear_maps);
- }
- }
- } else {
- if (!page->SweepingCompleted()) {
- heap_->mark_compact_collector()->SweepInParallel(page,
owner);
- if (!page->SweepingCompleted()) {
- // We were not able to sweep that page, i.e., a concurrent
- // sweeper thread currently owns this page.
- // TODO(hpayer): This may introduce a huge pause here. We
- // just care about finish sweeping of the scan on scavenge
page.
- heap_->mark_compact_collector()->EnsureSweepingCompleted();
- }
- }
- // TODO(hpayer): remove the special casing and merge map and
pointer
- // space handling as soon as we removed conservative sweeping.
- CHECK(page->owner() == heap_->old_pointer_space());
- if (heap_->old_pointer_space()->swept_precisely()) {
- HeapObjectIterator iterator(page, NULL);
- for (HeapObject* heap_object = iterator.Next();
- heap_object != NULL; heap_object = iterator.Next()) {
- // We iterate over objects that contain new space pointers
only.
- if (heap_object->MayContainNewSpacePointers()) {
- FindPointersToNewSpaceInRegion(
- heap_object->address() + HeapObject::kHeaderSize,
- heap_object->address() + heap_object->Size(),
- slot_callback, clear_maps);
- }
- }
- } else {
- FindPointersToNewSpaceInRegion(start, end, slot_callback,
- clear_maps);
- }
- }
- }
- }
- }
- if (callback_ != NULL) {
- (*callback_)(heap_, NULL, kStoreBufferScanningPageEvent);
- }
- }
-}
-
-
-void StoreBuffer::Compact() {
- Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
-
- if (top == start_) return;
-
- // There's no check of the limit in the loop below so we check here for
- // the worst case (compaction doesn't eliminate any pointers).
- DCHECK(top <= limit_);
- heap_->public_set_store_buffer_top(start_);
- EnsureSpace(top - start_);
- DCHECK(may_move_store_buffer_entries_);
- // Goes through the addresses in the store buffer attempting to remove
- // duplicates. In the interest of speed this is a lossy operation. Some
- // duplicates will remain. We have two hash sets with different hash
- // functions to reduce the number of unnecessary clashes.
- hash_sets_are_empty_ = false; // Hash sets are in use.
- for (Address* current = start_; current < top; current++) {
- DCHECK(!heap_->cell_space()->Contains(*current));
- DCHECK(!heap_->code_space()->Contains(*current));
- DCHECK(!heap_->old_data_space()->Contains(*current));
- uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current);
- // Shift out the last bits including any tags.
- int_addr >>= kPointerSizeLog2;
- // The upper part of an address is basically random because of ASLR
and OS
- // non-determinism, so we use only the bits within a page for hashing
to
- // make v8's behavior (more) deterministic.
- uintptr_t hash_addr =
- int_addr & (Page::kPageAlignmentMask >> kPointerSizeLog2);
- int hash1 = ((hash_addr ^ (hash_addr >> kHashSetLengthLog2)) &
- (kHashSetLength - 1));
- if (hash_set_1_[hash1] == int_addr) continue;
- uintptr_t hash2 = (hash_addr - (hash_addr >> kHashSetLengthLog2));
- hash2 ^= hash2 >> (kHashSetLengthLog2 * 2);
- hash2 &= (kHashSetLength - 1);
- if (hash_set_2_[hash2] == int_addr) continue;
- if (hash_set_1_[hash1] == 0) {
- hash_set_1_[hash1] = int_addr;
- } else if (hash_set_2_[hash2] == 0) {
- hash_set_2_[hash2] = int_addr;
- } else {
- // Rather than slowing down we just throw away some entries. This
will
- // cause some duplicates to remain undetected.
- hash_set_1_[hash1] = int_addr;
- hash_set_2_[hash2] = 0;
- }
- old_buffer_is_sorted_ = false;
- old_buffer_is_filtered_ = false;
- *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2);
- DCHECK(old_top_ <= old_limit_);
- }
- heap_->isolate()->counters()->store_buffer_compactions()->Increment();
-}
-
-} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/store-buffer.h Mon Aug 4 11:34:54 2014 UTC
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2011 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_STORE_BUFFER_H_
-#define V8_STORE_BUFFER_H_
-
-#include "src/allocation.h"
-#include "src/base/logging.h"
-#include "src/base/platform/platform.h"
-#include "src/globals.h"
-
-namespace v8 {
-namespace internal {
-
-class Page;
-class PagedSpace;
-class StoreBuffer;
-
-typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to);
-
-typedef void (StoreBuffer::*RegionCallback)(Address start,
- Address end,
- ObjectSlotCallback
slot_callback,
- bool clear_maps);
-
-// Used to implement the write barrier by collecting addresses of pointers
-// between spaces.
-class StoreBuffer {
- public:
- explicit StoreBuffer(Heap* heap);
-
- static void StoreBufferOverflow(Isolate* isolate);
-
- inline Address TopAddress();
-
- void SetUp();
- void TearDown();
-
- // This is used by the mutator to enter addresses into the store buffer.
- inline void Mark(Address addr);
-
- // This is used by the heap traversal to enter the addresses into the
store
- // buffer that should still be in the store buffer after GC. It enters
- // addresses directly into the old buffer because the GC starts by
wiping the
- // old buffer and thereafter only visits each cell once so there is no
need
- // to attempt to remove any dupes. During the first part of a GC we
- // are using the store buffer to access the old spaces and at the same
time
- // we are rebuilding the store buffer using this function. There is,
however
- // no issue of overwriting the buffer we are iterating over, because this
- // stage of the scavenge can only reduce the number of addresses in the
store
- // buffer (some objects are promoted so pointers to them do not need to
be in
- // the store buffer). The later parts of the GC scan the pages that are
- // exempt from the store buffer and process the promotion queue. These
steps
- // can overflow this buffer. We check for this and on overflow we call
the
- // callback set up with the StoreBufferRebuildScope object.
- inline void EnterDirectlyIntoStoreBuffer(Address addr);
-
- // Iterates over all pointers that go from old space to new space. It
will
- // delete the store buffer as it starts so the callback should reenter
- // surviving old-to-new pointers into the store buffer to rebuild it.
- void IteratePointersToNewSpace(ObjectSlotCallback callback);
-
- // Same as IteratePointersToNewSpace but additonally clears maps in
objects
- // referenced from the store buffer that do not contain a forwarding
pointer.
- void IteratePointersToNewSpaceAndClearMaps(ObjectSlotCallback callback);
-
- static const int kStoreBufferOverflowBit = 1 << (14 + kPointerSizeLog2);
- static const int kStoreBufferSize = kStoreBufferOverflowBit;
- static const int kStoreBufferLength = kStoreBufferSize / sizeof(Address);
- static const int kOldStoreBufferLength = kStoreBufferLength * 16;
- static const int kHashSetLengthLog2 = 12;
- static const int kHashSetLength = 1 << kHashSetLengthLog2;
-
- void Compact();
-
- void GCPrologue();
- void GCEpilogue();
-
- Object*** Limit() { return reinterpret_cast<Object***>(old_limit_); }
- Object*** Start() { return reinterpret_cast<Object***>(old_start_); }
- Object*** Top() { return reinterpret_cast<Object***>(old_top_); }
- void SetTop(Object*** top) {
- DCHECK(top >= Start());
- DCHECK(top <= Limit());
- old_top_ = reinterpret_cast<Address*>(top);
- }
-
- bool old_buffer_is_sorted() { return old_buffer_is_sorted_; }
- bool old_buffer_is_filtered() { return old_buffer_is_filtered_; }
-
- // Goes through the store buffer removing pointers to things that have
- // been promoted. Rebuilds the store buffer completely if it overflowed.
- void SortUniq();
-
- void EnsureSpace(intptr_t space_needed);
- void Verify();
-
- bool PrepareForIteration();
-
-#ifdef DEBUG
- void Clean();
- // Slow, for asserts only.
- bool CellIsInStoreBuffer(Address cell);
-#endif
-
- void Filter(int flag);
-
- private:
- Heap* heap_;
-
- // The store buffer is divided up into a new buffer that is constantly
being
- // filled by mutator activity and an old buffer that is filled with the
data
- // from the new buffer after compression.
- Address* start_;
- Address* limit_;
-
- Address* old_start_;
- Address* old_limit_;
- Address* old_top_;
- Address* old_reserved_limit_;
- base::VirtualMemory* old_virtual_memory_;
-
- bool old_buffer_is_sorted_;
- bool old_buffer_is_filtered_;
- bool during_gc_;
- // The garbage collector iterates over many pointers to new space that
are not
- // handled by the store buffer. This flag indicates whether the pointers
- // found by the callbacks should be added to the store buffer or not.
- bool store_buffer_rebuilding_enabled_;
- StoreBufferCallback callback_;
- bool may_move_store_buffer_entries_;
-
- base::VirtualMemory* virtual_memory_;
-
- // Two hash sets used for filtering.
- // If address is in the hash set then it is guaranteed to be in the
- // old part of the store buffer.
- uintptr_t* hash_set_1_;
- uintptr_t* hash_set_2_;
- bool hash_sets_are_empty_;
-
- void ClearFilteringHashSets();
-
- bool SpaceAvailable(intptr_t space_needed);
- void Uniq();
- void ExemptPopularPages(int prime_sample_step, int threshold);
-
- // Set the map field of the object to NULL if contains a map.
- inline void ClearDeadObject(HeapObject *object);
-
- void IteratePointersToNewSpace(ObjectSlotCallback callback, bool
clear_maps);
-
- void FindPointersToNewSpaceInRegion(Address start,
- Address end,
- ObjectSlotCallback slot_callback,
- bool clear_maps);
-
- // For each region of pointers on a page in use from an old space call
- // visit_pointer_region callback.
- // If either visit_pointer_region or callback can cause an allocation
- // in old space and changes in allocation watermark then
- // can_preallocate_during_iteration should be set to true.
- void IteratePointersOnPage(
- PagedSpace* space,
- Page* page,
- RegionCallback region_callback,
- ObjectSlotCallback slot_callback);
-
- void IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback,
- bool clear_maps);
-
-#ifdef VERIFY_HEAP
- void VerifyPointers(LargeObjectSpace* space);
-#endif
-
- friend class StoreBufferRebuildScope;
- friend class DontMoveStoreBufferEntriesScope;
-};
-
-
-class StoreBufferRebuildScope {
- public:
- explicit StoreBufferRebuildScope(Heap* heap,
- StoreBuffer* store_buffer,
- StoreBufferCallback callback)
- : store_buffer_(store_buffer),
- stored_state_(store_buffer->store_buffer_rebuilding_enabled_),
- stored_callback_(store_buffer->callback_) {
- store_buffer_->store_buffer_rebuilding_enabled_ = true;
- store_buffer_->callback_ = callback;
- (*callback)(heap, NULL, kStoreBufferStartScanningPagesEvent);
- }
-
- ~StoreBufferRebuildScope() {
- store_buffer_->callback_ = stored_callback_;
- store_buffer_->store_buffer_rebuilding_enabled_ = stored_state_;
- }
-
- private:
- StoreBuffer* store_buffer_;
- bool stored_state_;
- StoreBufferCallback stored_callback_;
-};
-
-
-class DontMoveStoreBufferEntriesScope {
- public:
- explicit DontMoveStoreBufferEntriesScope(StoreBuffer* store_buffer)
- : store_buffer_(store_buffer),
- stored_state_(store_buffer->may_move_store_buffer_entries_) {
- store_buffer_->may_move_store_buffer_entries_ = false;
- }
-
- ~DontMoveStoreBufferEntriesScope() {
- store_buffer_->may_move_store_buffer_entries_ = stored_state_;
- }
-
- private:
- StoreBuffer* store_buffer_;
- bool stored_state_;
-};
-
-} } // namespace v8::internal
-
-#endif // V8_STORE_BUFFER_H_
=======================================
--- /branches/bleeding_edge/BUILD.gn Sat Aug 9 10:02:42 2014 UTC
+++ /branches/bleeding_edge/BUILD.gn Mon Aug 11 14:22:24 2014 UTC
@@ -646,6 +646,9 @@
"src/heap/spaces-inl.h",
"src/heap/spaces.cc",
"src/heap/spaces.h",
+ "src/heap/store-buffer-inl.h",
+ "src/heap/store-buffer.cc",
+ "src/heap/store-buffer.h",
"src/heap/sweeper-thread.h",
"src/heap/sweeper-thread.cc",
"src/hydrogen-alias-analysis.h",
@@ -803,9 +806,6 @@
"src/snapshot-source-sink.cc",
"src/snapshot-source-sink.h",
"src/snapshot.h",
- "src/store-buffer-inl.h",
- "src/store-buffer.cc",
- "src/store-buffer.h",
"src/string-search.cc",
"src/string-search.h",
"src/string-stream.cc",
=======================================
--- /branches/bleeding_edge/src/assembler.cc Wed Aug 6 17:48:31 2014 UTC
+++ /branches/bleeding_edge/src/assembler.cc Mon Aug 11 14:22:24 2014 UTC
@@ -52,7 +52,6 @@
#include "src/regexp-stack.h"
#include "src/runtime.h"
#include "src/serialize.h"
-#include "src/store-buffer-inl.h"
#include "src/stub-cache.h"
#include "src/token.h"
=======================================
--- /branches/bleeding_edge/src/heap/heap-inl.h Tue Aug 5 08:18:22 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap-inl.h Mon Aug 11 14:22:24 2014 UTC
@@ -10,12 +10,12 @@
#include "src/base/platform/platform.h"
#include "src/cpu-profiler.h"
#include "src/heap/heap.h"
+#include "src/heap/store-buffer.h"
+#include "src/heap/store-buffer-inl.h"
#include "src/heap-profiler.h"
#include "src/isolate.h"
#include "src/list-inl.h"
#include "src/objects.h"
-#include "src/store-buffer.h"
-#include "src/store-buffer-inl.h"
namespace v8 {
namespace internal {
=======================================
--- /branches/bleeding_edge/src/heap/heap.cc Thu Aug 7 12:21:01 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap.cc Mon Aug 11 14:22:24 2014 UTC
@@ -20,13 +20,13 @@
#include "src/heap/mark-compact.h"
#include "src/heap/objects-visiting-inl.h"
#include "src/heap/objects-visiting.h"
+#include "src/heap/store-buffer.h"
#include "src/heap-profiler.h"
#include "src/isolate-inl.h"
#include "src/natives.h"
#include "src/runtime-profiler.h"
#include "src/scopeinfo.h"
#include "src/snapshot.h"
-#include "src/store-buffer.h"
#include "src/utils.h"
#include "src/v8threads.h"
#include "src/vm-state-inl.h"
=======================================
--- /branches/bleeding_edge/src/heap/heap.h Thu Aug 7 12:21:01 2014 UTC
+++ /branches/bleeding_edge/src/heap/heap.h Mon Aug 11 14:22:24 2014 UTC
@@ -16,9 +16,9 @@
#include "src/heap/mark-compact.h"
#include "src/heap/objects-visiting.h"
#include "src/heap/spaces.h"
+#include "src/heap/store-buffer.h"
#include "src/list.h"
#include "src/splay-tree-inl.h"
-#include "src/store-buffer.h"
namespace v8 {
namespace internal {
=======================================
--- /branches/bleeding_edge/src/heap/spaces.h Tue Aug 5 08:18:22 2014 UTC
+++ /branches/bleeding_edge/src/heap/spaces.h Mon Aug 11 14:22:24 2014 UTC
@@ -38,7 +38,7 @@
// may be larger than the page size.
//
// A store-buffer based write barrier is used to keep track of
intergenerational
-// references. See store-buffer.h.
+// references. See heap/store-buffer.h.
//
// During scavenges and mark-sweep collections we sometimes (after a store
// buffer overflow) iterate intergenerational pointers without decoding
heap
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Mon Aug 11 14:00:58 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h Mon Aug 11 14:22:24 2014 UTC
@@ -23,12 +23,12 @@
#include "src/heap/incremental-marking.h"
#include "src/heap/objects-visiting.h"
#include "src/heap/spaces.h"
+#include "src/heap/store-buffer.h"
#include "src/isolate.h"
#include "src/lookup.h"
#include "src/objects.h"
#include "src/property.h"
#include "src/prototype.h"
-#include "src/store-buffer.h"
#include "src/transitions-inl.h"
#include "src/v8memory.h"
=======================================
--- /branches/bleeding_edge/src/v8.cc Tue Aug 5 13:20:26 2014 UTC
+++ /branches/bleeding_edge/src/v8.cc Mon Aug 11 14:22:24 2014 UTC
@@ -13,6 +13,7 @@
#include "src/deoptimizer.h"
#include "src/elements.h"
#include "src/frames.h"
+#include "src/heap/store-buffer.h"
#include "src/heap-profiler.h"
#include "src/hydrogen.h"
#include "src/isolate.h"
@@ -21,7 +22,6 @@
#include "src/runtime-profiler.h"
#include "src/sampler.h"
#include "src/serialize.h"
-#include "src/store-buffer.h"
namespace v8 {
=======================================
--- /branches/bleeding_edge/tools/gyp/v8.gyp Fri Aug 8 11:42:59 2014 UTC
+++ /branches/bleeding_edge/tools/gyp/v8.gyp Mon Aug 11 14:22:24 2014 UTC
@@ -530,6 +530,9 @@
'../../src/heap/spaces-inl.h',
'../../src/heap/spaces.cc',
'../../src/heap/spaces.h',
+ '../../src/heap/store-buffer-inl.h',
+ '../../src/heap/store-buffer.cc',
+ '../../src/heap/store-buffer.h',
'../../src/heap/sweeper-thread.h',
'../../src/heap/sweeper-thread.cc',
'../../src/hydrogen-alias-analysis.h',
@@ -688,9 +691,6 @@
'../../src/snapshot.h',
'../../src/snapshot-source-sink.cc',
'../../src/snapshot-source-sink.h',
- '../../src/store-buffer-inl.h',
- '../../src/store-buffer.cc',
- '../../src/store-buffer.h',
'../../src/string-search.cc',
'../../src/string-search.h',
'../../src/string-stream.cc',
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.