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(&not_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

Reply via email to