Revision: 6201
Author: [email protected]
Date: Thu Jan 6 05:18:03 2011
Log: Fix/implement new write barrier for x64.
Review URL: http://codereview.chromium.org/6026017
http://code.google.com/p/v8/source/detail?r=6201
Added:
/branches/experimental/gc/src/write-buffer-inl.h
Modified:
/branches/experimental/gc/src/codegen.cc
/branches/experimental/gc/src/heap-inl.h
/branches/experimental/gc/src/heap.h
/branches/experimental/gc/src/ia32/assembler-ia32.h
/branches/experimental/gc/src/serialize.cc
/branches/experimental/gc/src/write-buffer.cc
/branches/experimental/gc/src/write-buffer.h
/branches/experimental/gc/src/x64/assembler-x64.h
/branches/experimental/gc/src/x64/code-stubs-x64.cc
/branches/experimental/gc/src/x64/code-stubs-x64.h
/branches/experimental/gc/src/x64/codegen-x64.cc
/branches/experimental/gc/src/x64/ic-x64.cc
/branches/experimental/gc/src/x64/macro-assembler-x64.cc
/branches/experimental/gc/src/x64/macro-assembler-x64.h
/branches/experimental/gc/src/x64/stub-cache-x64.cc
=======================================
--- /dev/null
+++ /branches/experimental/gc/src/write-buffer-inl.h Thu Jan 6 05:18:03
2011
@@ -0,0 +1,56 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_WRITE_BARRIER_INL_H_
+#define V8_WRITE_BARRIER_INL_H_
+
+#include "v8.h"
+#include "write-buffer.h"
+
+namespace v8 {
+namespace internal {
+
+Address WriteBuffer::TopAddress() {
+ return reinterpret_cast<Address>(Heap::write_buffer_top_address());
+}
+
+
+void WriteBuffer::Mark(Address addr) {
+ Address* top = reinterpret_cast<Address*>(Heap::write_buffer_top());
+ *top++ = addr;
+ Heap::public_set_write_buffer_top(top);
+ if ((reinterpret_cast<uintptr_t>(top) & kWriteBufferOverflowBit) != 0) {
+ ASSERT(top == limit_);
+ Compact();
+ } else {
+ ASSERT(top < limit_);
+ }
+}
+
+} } // namespace v8::internal
+
+#endif // V8_WRITE_BARRIER_INL_H_
=======================================
--- /branches/experimental/gc/src/codegen.cc Wed Jan 5 06:17:18 2011
+++ /branches/experimental/gc/src/codegen.cc Thu Jan 6 05:18:03 2011
@@ -473,11 +473,10 @@
int CEntryStub::MinorKey() {
int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0;
-#ifdef _WIN64
ASSERT(result_size_ == 1 || result_size_ == 2);
+#ifdef _WIN64
return result | ((result_size_ == 1) ? 0 : 2);
#else
- ASSERT(result_size_ == 1);
return result;
#endif
}
=======================================
--- /branches/experimental/gc/src/heap-inl.h Wed Jan 5 05:52:13 2011
+++ /branches/experimental/gc/src/heap-inl.h Thu Jan 6 05:18:03 2011
@@ -32,6 +32,7 @@
#include "objects.h"
#include "v8-counters.h"
#include "write-buffer.h"
+#include "write-buffer-inl.h"
namespace v8 {
namespace internal {
=======================================
--- /branches/experimental/gc/src/heap.h Wed Jan 5 05:52:13 2011
+++ /branches/experimental/gc/src/heap.h Thu Jan 6 05:18:03 2011
@@ -48,6 +48,7 @@
V(Map, two_pointer_filler_map,
TwoPointerFillerMap) \
/* Cluster the most popular ones in a few cache lines here at the
top. */ \
V(Smi, stack_limit,
StackLimit) \
+ V(Smi, write_buffer_top,
WriteBufferTop) \
V(Object, undefined_value,
UndefinedValue) \
V(Object, the_hole_value,
TheHoleValue) \
V(Object, null_value,
NullValue) \
@@ -904,12 +905,20 @@
static void public_set_empty_script(Script* script) {
roots_[kEmptyScriptRootIndex] = script;
}
+
+ static void public_set_write_buffer_top(Address* top) {
+ roots_[kWriteBufferTopRootIndex] = reinterpret_cast<Smi*>(top);
+ }
// Update the next script id.
static inline void SetLastScriptId(Object* last_script_id);
// Generated code can embed this address to get access to the roots.
static Object** roots_address() { return roots_; }
+
+ static Address* write_buffer_top_address() {
+ return reinterpret_cast<Address*>(&roots_[kWriteBufferTopRootIndex]);
+ }
// Get address of global contexts list for serialization support.
static Object** global_contexts_list_address() {
=======================================
--- /branches/experimental/gc/src/ia32/assembler-ia32.h Tue Dec 21 04:32:46
2010
+++ /branches/experimental/gc/src/ia32/assembler-ia32.h Thu Jan 6 05:18:03
2011
@@ -90,6 +90,8 @@
}
static Register from_code(int code) {
+ ASSERT(code >= 0);
+ ASSERT(code < kNumRegisters);
Register r = { code };
return r;
}
=======================================
--- /branches/experimental/gc/src/serialize.cc Wed Jan 5 06:17:18 2011
+++ /branches/experimental/gc/src/serialize.cc Thu Jan 6 05:18:03 2011
@@ -652,6 +652,8 @@
void Deserializer::Deserialize() {
// Don't GC while deserializing - just expand the heap.
+ Address* write_buffer_top =
+ reinterpret_cast<Address*>(Heap::write_buffer_top());
AlwaysAllocateScope always_allocate;
// Don't use the free lists while deserializing.
LinearAllocationScope allocate_linearly;
@@ -668,6 +670,7 @@
Heap::IterateWeakRoots(this, VISIT_ALL);
Heap::set_global_contexts_list(Heap::undefined_value());
+ Heap::public_set_write_buffer_top(write_buffer_top);
}
=======================================
--- /branches/experimental/gc/src/write-buffer.cc Wed Jan 5 06:17:18 2011
+++ /branches/experimental/gc/src/write-buffer.cc Thu Jan 6 05:18:03 2011
@@ -27,11 +27,11 @@
#include "v8-counters.h"
#include "write-buffer.h"
+#include "write-buffer-inl.h"
namespace v8 {
namespace internal {
-Address* WriteBuffer::top_ = NULL;
Address* WriteBuffer::start_ = NULL;
Address* WriteBuffer::limit_ = NULL;
uintptr_t* WriteBuffer::hash_map_1_ = NULL;
@@ -61,7 +61,7 @@
virtual_memory_->Commit(reinterpret_cast<Address>(start_),
kWriteBufferSize,
false); // Not executable.
- top_ = start_;
+ Heap::public_set_write_buffer_top(start_);
hash_map_1_ = new uintptr_t[kHashMapLength];
hash_map_2_ = new uintptr_t[kHashMapLength];
@@ -72,7 +72,8 @@
delete virtual_memory_;
delete[] hash_map_1_;
delete[] hash_map_2_;
- top_ = start_ = limit_ = NULL;
+ start_ = limit_ = NULL;
+ Heap::public_set_write_buffer_top(start_);
}
@@ -83,9 +84,10 @@
memset(reinterpret_cast<void*>(hash_map_2_),
0,
sizeof(uintptr_t) * kHashMapLength);
- ASSERT(top_ <= limit_);
- Address* stop = top_;
- top_ = start_;
+ Address* top = reinterpret_cast<Address*>(Heap::write_buffer_top());
+ Address* stop = top;
+ ASSERT(top <= limit_);
+ top = start_;
// Goes through the addresses in the write buffer attempting to remove
// duplicates. In the interest of speed this is a lossy operation. Some
// duplicates will remain. We have two hash tables with different hash
@@ -111,23 +113,24 @@
hash_map_1_[hash1] = int_addr;
hash_map_2_[hash2] = 0;
}
- ASSERT(top_ <= current);
- ASSERT(top_ <= limit_);
- *top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2);
+ ASSERT(top <= current);
+ ASSERT(top <= limit_);
+ *top++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2);
}
Counters::write_buffer_compactions.Increment();
- if (limit_ - top_ < top_ - start_) {
+ if (limit_ - top < top - start_) {
// Compression did not free up at least half.
// TODO(gc): Set an interrupt to do a GC on the next back edge.
// TODO(gc): Allocate the rest of new space to force a GC on the next
// allocation.
- if (limit_ - top_ < (top_ - start_) >> 1) {
+ if (limit_ - top < (top - start_) >> 1) {
// Compression did not free up at least one quarter.
// TODO(gc): Set a flag to scan all of memory.
- top_ = start_;
+ top = start_;
Counters::write_buffer_overflows.Increment();
}
}
+ Heap::public_set_write_buffer_top(top);
}
} } // namespace v8::internal
=======================================
--- /branches/experimental/gc/src/write-buffer.h Wed Jan 5 06:17:18 2011
+++ /branches/experimental/gc/src/write-buffer.h Thu Jan 6 05:18:03 2011
@@ -41,20 +41,12 @@
// between spaces.
class WriteBuffer : public AllStatic {
public:
- static Address TopAddress() { return reinterpret_cast<Address>(&top_); }
+ static inline Address TopAddress();
static void Setup();
static void TearDown();
- static inline void Mark(Address addr) {
- *top_++ = addr;
- if ((reinterpret_cast<uintptr_t>(top_) & kWriteBufferOverflowBit) !=
0) {
- ASSERT(top_ == limit_);
- Compact();
- } else {
- ASSERT(top_ < limit_);
- }
- }
+ static inline void Mark(Address addr);
static const int kWriteBufferOverflowBit = 1 << 16;
static const int kWriteBufferSize = kWriteBufferOverflowBit;
@@ -64,7 +56,6 @@
static void Compact();
private:
- static Address* top_;
static Address* start_;
static Address* limit_;
static VirtualMemory* virtual_memory_;
=======================================
--- /branches/experimental/gc/src/x64/assembler-x64.h Wed Jan 5 05:52:13
2011
+++ /branches/experimental/gc/src/x64/assembler-x64.h Thu Jan 6 05:18:03
2011
@@ -195,6 +195,12 @@
return names[index];
}
+ static XMMRegister from_code(int code) {
+ ASSERT(code >= 0);
+ ASSERT(code < kNumRegisters);
+ XMMRegister r = { code };
+ return r;
+ }
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
int code() const {
ASSERT(is_valid());
=======================================
--- /branches/experimental/gc/src/x64/code-stubs-x64.cc Wed Jan 5 05:52:13
2011
+++ /branches/experimental/gc/src/x64/code-stubs-x64.cc Thu Jan 6 05:18:03
2011
@@ -253,6 +253,45 @@
__ Set(rax, 0);
__ ret(1 * kPointerSize);
}
+
+
+void WriteBufferOverflowStub::Generate(MacroAssembler* masm) {
+ // We don't allow a GC during a write buffer overflow so there is no
need to
+ // store the registers in any particular way, but we do have to store and
+ // restore them.
+ Register saved_regs[] =
+ { rax, rcx, rdx, rbx, rbp, rsi, rdi, r8, r9, r10, r11 };
+ const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
+ for (int i = 0; i < kNumberOfSavedRegs; i++) {
+ __ push(saved_regs[i]);
+ }
+ // R12 to r15 are callee save on all platforms.
+ if (save_doubles_ == kSaveFPRegs) {
+ CpuFeatures::Scope scope(SSE2);
+ __ subq(rsp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
+ for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
+ XMMRegister reg = XMMRegister::from_code(i);
+ __ movsd(Operand(rsp, i * kDoubleSize), reg);
+ }
+ }
+ const int argument_count = 0;
+ __ PrepareCallCFunction(argument_count);
+ ExternalReference write_buffer_overflow =
+
ExternalReference(Runtime::FunctionForId(Runtime::kWriteBufferOverflow));
+ __ CallCFunction(write_buffer_overflow, argument_count);
+ if (save_doubles_ == kSaveFPRegs) {
+ CpuFeatures::Scope scope(SSE2);
+ for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
+ XMMRegister reg = XMMRegister::from_code(i);
+ __ movsd(reg, Operand(rsp, i * kDoubleSize));
+ }
+ __ addq(rsp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
+ }
+ for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) {
+ __ pop(saved_regs[i]);
+ }
+ __ ret(0);
+}
const char* GenericBinaryOpStub::GetName() {
@@ -1971,16 +2010,16 @@
// Store last subject and last input.
__ movq(rax, Operand(rsp, kSubjectOffset));
__ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
__ movq(rcx, rbx);
- __ RecordWrite(rcx, RegExpImpl::kLastSubjectOffset, rax, rdi);
-#endif
+ __ RecordWrite(rcx,
+ RegExpImpl::kLastSubjectOffset,
+ rax,
+ rdi,
+ kDontSaveFPRegs);
__ movq(rax, Operand(rsp, kSubjectOffset));
__ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
__ movq(rcx, rbx);
- __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi);
-#endif
+ __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi,
kDontSaveFPRegs);
// Get the static offsets vector filled by the native regexp code.
__ movq(rcx, ExternalReference::address_of_static_offsets_vector());
=======================================
--- /branches/experimental/gc/src/x64/code-stubs-x64.h Wed Jan 5 05:52:13
2011
+++ /branches/experimental/gc/src/x64/code-stubs-x64.h Thu Jan 6 05:18:03
2011
@@ -63,6 +63,21 @@
};
+class WriteBufferOverflowStub: public CodeStub {
+ public:
+ explicit WriteBufferOverflowStub(SaveFPRegsMode save_fp)
+ : save_doubles_(save_fp) { }
+
+ void Generate(MacroAssembler* masm);
+
+ private:
+ SaveFPRegsMode save_doubles_;
+
+ Major MajorKey() { return WriteBufferOverflow; }
+ int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
+};
+
+
// Flag that indicates how to generate code for the stub
GenericBinaryOpStub.
enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0,
=======================================
--- /branches/experimental/gc/src/x64/codegen-x64.cc Wed Jan 5 05:52:13
2011
+++ /branches/experimental/gc/src/x64/codegen-x64.cc Thu Jan 6 05:18:03
2011
@@ -262,14 +262,16 @@
Result context = allocator_->Allocate();
ASSERT(context.is_valid());
__ movq(SlotOperand(slot, context.reg()), value.reg());
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
int offset = FixedArray::kHeaderSize + slot->index() *
kPointerSize;
Result scratch = allocator_->Allocate();
ASSERT(scratch.is_valid());
frame_->Spill(context.reg());
frame_->Spill(value.reg());
- __ RecordWrite(context.reg(), offset, value.reg(),
scratch.reg());
-#endif
+ __ RecordWrite(context.reg(),
+ offset,
+ value.reg(),
+ scratch.reg(),
+ kDontSaveFPRegs);
}
}
}
@@ -4655,7 +4657,6 @@
Result start = allocator_->Allocate();
ASSERT(start.is_valid());
__ movq(SlotOperand(slot, start.reg()), value.reg());
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
// RecordWrite may destroy the value registers.
//
// TODO(204): Avoid actually spilling when the value is not
@@ -4664,8 +4665,11 @@
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
Result temp = allocator_->Allocate();
ASSERT(temp.is_valid());
- __ RecordWrite(start.reg(), offset, value.reg(), temp.reg());
-#endif
+ __ RecordWrite(start.reg(),
+ offset,
+ value.reg(),
+ temp.reg(),
+ kDontSaveFPRegs);
// The results start, value, and temp are unused by going out of
// scope.
}
@@ -5016,11 +5020,13 @@
// Update the write barrier for the array address.
frame_->Spill(prop_value.reg()); // Overwritten by the write barrier.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
Result scratch = allocator_->Allocate();
ASSERT(scratch.is_valid());
- __ RecordWrite(elements.reg(), offset, prop_value.reg(),
scratch.reg());
-#endif
+ __ RecordWrite(elements.reg(),
+ offset,
+ prop_value.reg(),
+ scratch.reg(),
+ kDontSaveFPRegs);
}
}
@@ -6348,10 +6354,11 @@
// The object register is also overwritten by the write barrier and
// possibly aliased in the frame.
frame_->Spill(object.reg());
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
- __ RecordWrite(object.reg(), JSValue::kValueOffset,
duplicate_value.reg(),
- scratch.reg());
-#endif
+ __ RecordWrite(object.reg(),
+ JSValue::kValueOffset,
+ duplicate_value.reg(),
+ scratch.reg(),
+ kDontSaveFPRegs);
object.Unuse();
scratch.Unuse();
duplicate_value.Unuse();
@@ -6632,9 +6639,7 @@
FieldOperand(rcx, JSFunctionResultCache::kFingerOffset), r9);
// Store key.
__ movq(ArrayElement(rcx, r9), rbx);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
- __ RecordWrite(rcx, 0, rbx, r9);
-#endif
+ __ RecordWrite(rcx, 0, rbx, r9, kDontSaveFPRegs);
// Store value.
__ pop(rcx); // restore the cache.
@@ -6644,9 +6649,7 @@
// Backup rax, because the RecordWrite macro clobbers its arguments.
__ movq(rbx, rax);
__ movq(ArrayElement(rcx, rdx), rax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
- __ RecordWrite(rcx, 0, rbx, rdx);
-#endif
+ __ RecordWrite(rcx, 0, rbx, rdx, kDontSaveFPRegs);
if (!dst_.is(rax)) {
__ movq(dst_, rax);
@@ -6819,17 +6822,15 @@
__ movq(Operand(index2.reg(), 0), object.reg());
__ movq(Operand(index1.reg(), 0), tmp2.reg());
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
Label done;
__ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done);
// Possible optimization: do a check that both values are Smis
// (or them and test against Smi mask.)
__ movq(tmp2.reg(), tmp1.reg());
- __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg());
- __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg());
+ __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg(),
kDontSaveFPRegs);
+ __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg(),
kDontSaveFPRegs);
__ bind(&done);
-#endif
deferred->BindExit();
frame_->Push(Factory::undefined_value());
@@ -8324,23 +8325,20 @@
// Update the write barrier. To save instructions in the inlined
// version we do not filter smis.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
Label skip_write_barrier;
__ InNewSpace(receiver.reg(), value.reg(), equal, &skip_write_barrier);
int delta_to_record_write =
masm_->SizeOfCodeGeneratedSince(&patch_site);
__ lea(scratch.reg(), Operand(receiver.reg(), offset));
- __ RecordWriteHelper(receiver.reg(), scratch.reg(), value.reg());
+ __ RecordWriteHelper(receiver.reg(),
+ scratch.reg(),
+ value.reg(),
+ kDontSaveFPRegs);
if (FLAG_debug_code) {
__ movq(receiver.reg(), BitCast<int64_t>(kZapValue),
RelocInfo::NONE);
__ movq(value.reg(), BitCast<int64_t>(kZapValue), RelocInfo::NONE);
__ movq(scratch.reg(), BitCast<int64_t>(kZapValue), RelocInfo::NONE);
}
__ bind(&skip_write_barrier);
-#else
- // Use dummy delta to record write value to ensure proper
- // testl encoding.
- int delta_to_record_write = 0x0001;
-#endif
value.Unuse();
scratch.Unuse();
receiver.Unuse();
@@ -8478,11 +8476,9 @@
Result tmp2 = allocator_->Allocate();
ASSERT(tmp2.is_valid());
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
// Determine whether the value is a constant before putting it in a
// register.
bool value_is_constant = result.is_constant();
-#endif
// Make sure that value, key and receiver are in registers.
result.ToRegister();
@@ -8522,7 +8518,6 @@
// Check whether it is possible to omit the write barrier. If the
elements
// array is in new space or the value written is a smi we can safely
update
// the elements array without write barrier.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
Label in_new_space;
__ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space);
if (!value_is_constant) {
@@ -8530,7 +8525,6 @@
}
__ bind(&in_new_space);
-#endif
// Bind the deferred code patch site to be able to locate the fixed
// array map comparison. When debugging, we patch this comparison to
=======================================
--- /branches/experimental/gc/src/x64/ic-x64.cc Wed Jan 5 05:52:13 2011
+++ /branches/experimental/gc/src/x64/ic-x64.cc Thu Jan 6 05:18:03 2011
@@ -269,10 +269,8 @@
__ movq(Operand(scratch1, 0), value);
// Update write barrier. Make sure not to clobber the value.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
__ movq(scratch0, value);
- __ RecordWrite(elements, scratch1, scratch0);
-#endif
+ __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs);
}
@@ -1019,10 +1017,8 @@
__ bind(&non_smi_value);
// Slow case that needs to retain rcx for use by RecordWrite.
// Update write barrier for the elements array address.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
__ movq(rdx, rax);
- __ RecordWriteNonSmi(rbx, 0, rdx, rcx);
-#endif
+ __ RecordWriteNonSmi(rbx, 0, rdx, rcx, kDontSaveFPRegs);
__ ret(0);
}
@@ -1638,9 +1634,7 @@
Address encoded_offsets_address = test_instruction_address + 1;
int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
int delta_to_map_check = -(encoded_offsets & 0xFFFF);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
int delta_to_record_write = encoded_offsets >> 16;
-#endif
// Patch the map to check. The map address is the last 8 bytes of
// the 10-byte immediate move instruction.
@@ -1659,7 +1653,6 @@
(offset == 0 && map == Heap::null_value()));
*reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
// Patch the offset in the write-barrier code. The offset is the
// last 4 bytes of a 7 byte lea instruction.
offset_address = map_check_address + delta_to_record_write + 3;
@@ -1669,7 +1662,6 @@
*reinterpret_cast<int*>(offset_address) == -1 ||
(offset == 0 && map == Heap::null_value()));
*reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
-#endif
return true;
}
=======================================
--- /branches/experimental/gc/src/x64/macro-assembler-x64.cc Wed Jan 5
05:52:13 2011
+++ /branches/experimental/gc/src/x64/macro-assembler-x64.cc Thu Jan 6
05:18:03 2011
@@ -73,10 +73,11 @@
cmpq(with, kScratchRegister);
}
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
+
void MacroAssembler::RecordWriteHelper(Register object,
Register addr,
- Register scratch) {
+ Register scratch,
+ SaveFPRegsMode save_fp) {
if (FLAG_debug_code) {
// Check that the object is not in new space.
NearLabel not_in_new_space;
@@ -85,24 +86,31 @@
bind(¬_in_new_space);
}
- // Compute the page start address from the heap object pointer, and reuse
- // the 'object' register for it.
- and_(object, Immediate(~Page::kPageAlignmentMask));
-
- // Compute number of region covering addr. See
Page::GetRegionNumberForAddress
- // method for more details.
- shrl(addr, Immediate(Page::kRegionSizeLog2));
- andl(addr, Immediate(Page::kPageAlignmentMask >> Page::kRegionSizeLog2));
-
- // Set dirty mark for region.
- bts(Operand(object, Page::kDirtyFlagOffset), addr);
+ // Load write buffer top.
+ LoadRoot(scratch, Heap::kWriteBufferTopRootIndex);
+ // Store pointer to buffer.
+ movq(Operand(scratch, 0), addr);
+ // Increment buffer top.
+ addq(scratch, Immediate(kPointerSize));
+ // Write back new top of buffer.
+ StoreRoot(scratch, Heap::kWriteBufferTopRootIndex);
+ // Call stub on end of buffer.
+ NearLabel no_overflow;
+ // Check for end of buffer.
+ testq(scratch, Immediate(WriteBuffer::kWriteBufferOverflowBit));
+ j(equal, &no_overflow);
+ WriteBufferOverflowStub write_buffer_overflow =
+ WriteBufferOverflowStub(save_fp);
+ CallStub(&write_buffer_overflow);
+ bind(&no_overflow);
}
void MacroAssembler::RecordWrite(Register object,
int offset,
Register value,
- Register index) {
+ Register index,
+ SaveFPRegsMode save_fp) {
// The compiled code assumes that record write doesn't change the
// context register, so we check that none of the clobbered
// registers are rsi.
@@ -113,7 +121,7 @@
Label done;
JumpIfSmi(value, &done);
- RecordWriteNonSmi(object, offset, value, index);
+ RecordWriteNonSmi(object, offset, value, index, save_fp);
bind(&done);
// Clobber all input registers when running with the debug-code flag
@@ -131,7 +139,8 @@
void MacroAssembler::RecordWrite(Register object,
Register address,
- Register value) {
+ Register value,
+ SaveFPRegsMode save_fp) {
// The compiled code assumes that record write doesn't change the
// context register, so we check that none of the clobbered
// registers are esi.
@@ -144,7 +153,7 @@
InNewSpace(object, value, equal, &done);
- RecordWriteHelper(object, address, value);
+ RecordWriteHelper(object, address, value, save_fp);
bind(&done);
@@ -161,7 +170,8 @@
void MacroAssembler::RecordWriteNonSmi(Register object,
int offset,
Register scratch,
- Register index) {
+ Register index,
+ SaveFPRegsMode save_fp) {
Label done;
if (FLAG_debug_code) {
@@ -202,7 +212,7 @@
times_pointer_size,
FixedArray::kHeaderSize));
}
- RecordWriteHelper(object, dst, scratch);
+ RecordWriteHelper(object, dst, scratch, save_fp);
bind(&done);
@@ -214,7 +224,7 @@
movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
}
}
-#endif
+
void MacroAssembler::Assert(Condition cc, const char* msg) {
if (FLAG_debug_code) Check(cc, msg);
=======================================
--- /branches/experimental/gc/src/x64/macro-assembler-x64.h Wed Jan 5
05:52:13 2011
+++ /branches/experimental/gc/src/x64/macro-assembler-x64.h Thu Jan 6
05:18:03 2011
@@ -81,13 +81,13 @@
//
---------------------------------------------------------------------------
// GC Support
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
// For page containing |object| mark region covering |addr| dirty.
// RecordWriteHelper only works if the object is not in new
// space.
void RecordWriteHelper(Register object,
Register addr,
- Register scratch);
+ Register scratch,
+ SaveFPRegsMode save_fp);
// Check if object is in new space. The condition cc can be equal or
// not_equal. If it is equal a jump will be done if the object is on new
@@ -108,7 +108,8 @@
void RecordWrite(Register object,
int offset,
Register value,
- Register scratch);
+ Register scratch,
+ SaveFPRegsMode save_fp);
// For page containing |object| mark region covering [address]
// dirty. |object| is the object being stored into, |value| is the
@@ -117,7 +118,8 @@
// the write barrier if the value is a smi.
void RecordWrite(Register object,
Register address,
- Register value);
+ Register value,
+ SaveFPRegsMode save_fp);
// For page containing |object| mark region covering [object+offset]
dirty.
// The value is known to not be a smi.
@@ -128,8 +130,8 @@
void RecordWriteNonSmi(Register object,
int offset,
Register value,
- Register scratch);
-#endif
+ Register scratch,
+ SaveFPRegsMode save_fp);
#ifdef ENABLE_DEBUGGER_SUPPORT
//
---------------------------------------------------------------------------
@@ -1650,7 +1652,6 @@
}
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
template <typename LabelType>
void MacroAssembler::InNewSpace(Register object,
Register scratch,
@@ -1685,7 +1686,7 @@
j(cc, branch);
}
}
-#endif
+
template <typename LabelType>
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
=======================================
--- /branches/experimental/gc/src/x64/stub-cache-x64.cc Wed Jan 5 05:52:13
2011
+++ /branches/experimental/gc/src/x64/stub-cache-x64.cc Thu Jan 6 05:18:03
2011
@@ -1449,10 +1449,7 @@
__ j(not_equal, &call_builtin);
if (argc == 1) { // Otherwise fall through to call builtin.
- Label exit, attempt_to_grow_elements;
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
- Label with_write_barrier;
-#endif
+ Label exit, attempt_to_grow_elements, with_write_barrier;
// Get the array's length into rax and calculate new length.
__ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
@@ -1479,22 +1476,18 @@
// Check if value is a smi.
__ Integer32ToSmi(rax, rax); // Return new length as smi.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
__ JumpIfNotSmi(rcx, &with_write_barrier);
-#endif
__ bind(&exit);
__ ret((argc + 1) * kPointerSize);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
__ bind(&with_write_barrier);
__ InNewSpace(rbx, rcx, equal, &exit);
- __ RecordWriteHelper(rbx, rdx, rcx);
+ __ RecordWriteHelper(rbx, rdx, rcx, kDontSaveFPRegs);
__ ret((argc + 1) * kPointerSize);
-#endif
__ bind(&attempt_to_grow_elements);
if (!FLAG_inline_new) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev