Revision: 6184
Author: [email protected]
Date: Wed Jan  5 06:17:18 2011
Log: Write buffer based write barrier for IA32 and Crankshaft.  Currently
coverage is untested, but believed to be complete.
Review URL: http://codereview.chromium.org/6092007
http://code.google.com/p/v8/source/detail?r=6184

Modified:
 /branches/experimental/gc/src/assembler.h
 /branches/experimental/gc/src/code-stubs.h
 /branches/experimental/gc/src/codegen.cc
 /branches/experimental/gc/src/ia32/code-stubs-ia32.cc
 /branches/experimental/gc/src/ia32/code-stubs-ia32.h
 /branches/experimental/gc/src/ia32/codegen-ia32.cc
 /branches/experimental/gc/src/ia32/full-codegen-ia32.cc
 /branches/experimental/gc/src/ia32/ic-ia32.cc
 /branches/experimental/gc/src/ia32/lithium-codegen-ia32.cc
 /branches/experimental/gc/src/ia32/macro-assembler-ia32.cc
 /branches/experimental/gc/src/ia32/macro-assembler-ia32.h
 /branches/experimental/gc/src/ia32/stub-cache-ia32.cc
 /branches/experimental/gc/src/runtime.cc
 /branches/experimental/gc/src/runtime.h
 /branches/experimental/gc/src/serialize.cc
 /branches/experimental/gc/src/write-buffer.cc
 /branches/experimental/gc/src/write-buffer.h
 /branches/experimental/gc/test/cctest/test-alloc.cc

=======================================
--- /branches/experimental/gc/src/assembler.h   Tue Dec 21 04:32:46 2010
+++ /branches/experimental/gc/src/assembler.h   Wed Jan  5 06:17:18 2011
@@ -152,6 +152,9 @@
 };


+enum SaveFPRegsMode { kDontSaveFPRegs, kSaveFPRegs };
+
+
// -----------------------------------------------------------------------------
 // Relocation information

=======================================
--- /branches/experimental/gc/src/code-stubs.h  Wed Jan  5 05:52:13 2011
+++ /branches/experimental/gc/src/code-stubs.h  Wed Jan  5 06:17:18 2011
@@ -47,6 +47,7 @@
   V(Compare)                             \
   V(CompareIC)                           \
   V(MathPow)                             \
+  V(WriteBufferOverflow)                 \
   V(TranscendentalCache)                 \
   V(RecordWrite)                         \
   V(ConvertToDouble)                     \
@@ -572,11 +573,11 @@

 class CEntryStub : public CodeStub {
  public:
-  explicit CEntryStub(int result_size)
-      : result_size_(result_size), save_doubles_(false) { }
+  explicit CEntryStub(int result_size,
+                      SaveFPRegsMode save_doubles = kDontSaveFPRegs)
+      : result_size_(result_size), save_doubles_(save_doubles) { }

   void Generate(MacroAssembler* masm);
-  void SaveDoubles() { save_doubles_ = true; }

  private:
   void GenerateCore(MacroAssembler* masm,
@@ -592,7 +593,7 @@

   // Number of pointers/values returned.
   const int result_size_;
-  bool save_doubles_;
+  SaveFPRegsMode save_doubles_;

   Major MajorKey() { return CEntry; }
   int MinorKey();
=======================================
--- /branches/experimental/gc/src/codegen.cc    Tue Dec 21 04:32:46 2010
+++ /branches/experimental/gc/src/codegen.cc    Wed Jan  5 06:17:18 2011
@@ -472,11 +472,12 @@


 int CEntryStub::MinorKey() {
-  ASSERT(result_size_ == 1 || result_size_ == 2);
-  int result = save_doubles_ ? 1 : 0;
+  int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0;
 #ifdef _WIN64
+  ASSERT(result_size_ == 1 || result_size_ == 2);
   return result | ((result_size_ == 1) ? 0 : 2);
 #else
+  ASSERT(result_size_ == 1);
   return result;
 #endif
 }
=======================================
--- /branches/experimental/gc/src/ia32/code-stubs-ia32.cc Wed Jan 5 05:52:13 2011 +++ /branches/experimental/gc/src/ia32/code-stubs-ia32.cc Wed Jan 5 06:17:18 2011
@@ -257,6 +257,37 @@
   __ mov(eax, 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.
+  __ pushad();
+  if (save_doubles_ == kSaveFPRegs) {
+    CpuFeatures::Scope scope(SSE2);
+ __ sub(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters));
+    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
+      XMMRegister reg = XMMRegister::from_code(i);
+      __ movdbl(Operand(esp, i * kDoubleSize), reg);
+    }
+  }
+  const int argument_count = 0;
+  __ PrepareCallCFunction(argument_count, ecx);
+  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);
+      __ movdbl(reg, Operand(esp, i * kDoubleSize));
+    }
+ __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters));
+  }
+  __ popad();
+  __ ret(0);
+}


 const char* GenericBinaryOpStub::GetName() {
@@ -3981,16 +4012,16 @@
   // Store last subject and last input.
   __ mov(eax, Operand(esp, kSubjectOffset));
   __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   __ mov(ecx, ebx);
-  __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi);
-#endif
+  __ RecordWrite(ecx,
+                 RegExpImpl::kLastSubjectOffset,
+                 eax,
+                 edi,
+                 kDontSaveFPRegs);
   __ mov(eax, Operand(esp, kSubjectOffset));
   __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   __ mov(ecx, ebx);
-  __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi);
-#endif
+ __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi, kDontSaveFPRegs);

   // Get the static offsets vector filled by the native regexp code.
   ExternalReference address_of_static_offsets_vector =
@@ -4728,7 +4759,7 @@
   __ j(zero, &failure_returned, not_taken);

   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame(save_doubles_);
+  __ LeaveExitFrame(save_doubles_ == kSaveFPRegs);
   __ ret(0);

   // Handling of failure.
@@ -4828,7 +4859,7 @@
   // a garbage collection and retrying the builtin (twice).

   // Enter the exit frame that transitions from JavaScript to C++.
-  __ EnterExitFrame(save_doubles_);
+  __ EnterExitFrame(save_doubles_ == kSaveFPRegs);

   // eax: result parameter for PerformGC, if any (setup below)
   // ebx: pointer to builtin function  (C callee-saved)
=======================================
--- /branches/experimental/gc/src/ia32/code-stubs-ia32.h Tue Dec 21 04:32:46 2010 +++ /branches/experimental/gc/src/ia32/code-stubs-ia32.h Wed Jan 5 06:17:18 2011
@@ -72,6 +72,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/ia32/codegen-ia32.cc Thu Dec 23 08:04:56 2010 +++ /branches/experimental/gc/src/ia32/codegen-ia32.cc Wed Jan 5 06:17:18 2011
@@ -265,14 +265,16 @@
           Result context = allocator_->Allocate();
           ASSERT(context.is_valid());
           __ mov(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);
         }
       }
     }
@@ -5311,7 +5313,6 @@
       ASSERT(start.is_valid());
       __ mov(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
@@ -5320,10 +5321,13 @@
       int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
       Result temp = allocator_->Allocate();
       ASSERT(temp.is_valid());
-      __ RecordWrite(start.reg(), offset, value.reg(), temp.reg());
+      __ RecordWrite(start.reg(),
+                     offset,
+                     value.reg(),
+                     temp.reg(),
+                     kDontSaveFPRegs);
       // The results start, value, and temp are unused by going out of
       // scope.
-#endif
     }

     exit.Bind();
@@ -5710,13 +5714,15 @@
     int offset = i * kPointerSize + FixedArray::kHeaderSize;
     __ mov(FieldOperand(elements.reg(), offset), prop_value.reg());

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
     // Update the write barrier for the array address.
     frame_->Spill(prop_value.reg());  // Overwritten by the 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);
   }
 }

@@ -7246,7 +7252,6 @@
   // Store the value.
   __ mov(FieldOperand(object.reg(), JSValue::kValueOffset), value.reg());

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   // Update the write barrier.  Save the value as it will be
   // overwritten by the write barrier code and is needed afterward.
   Result duplicate_value = allocator_->Allocate();
@@ -7256,9 +7261,8 @@
   // possibly aliased in the frame.
   frame_->Spill(object.reg());
__ RecordWrite(object.reg(), JSValue::kValueOffset, duplicate_value.reg(),
-                 scratch.reg());
+                 scratch.reg(), kDontSaveFPRegs);
   duplicate_value.Unuse();
-#endif

   object.Unuse();
   scratch.Unuse();
@@ -7531,9 +7535,7 @@
   __ mov(FieldOperand(ecx, JSFunctionResultCache::kFingerOffset), edx);
   // Store key.
   __ mov(CodeGenerator::FixedArrayElementOperand(ecx, edx), ebx);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
-  __ RecordWrite(ecx, 0, ebx, edx);
-#endif
+  __ RecordWrite(ecx, 0, ebx, edx, kDontSaveFPRegs);

   // Store value.
   __ pop(ecx);  // restore the cache.
@@ -7541,9 +7543,7 @@
   __ add(Operand(edx), Immediate(Smi::FromInt(1)));
   __ mov(ebx, eax);
   __ mov(CodeGenerator::FixedArrayElementOperand(ecx, edx), ebx);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
-  __ RecordWrite(ecx, 0, ebx, edx);
-#endif
+  __ RecordWrite(ecx, 0, ebx, edx, kDontSaveFPRegs);

   if (!dst_.is(eax)) {
     __ mov(dst_, eax);
@@ -7708,17 +7708,15 @@
   __ mov(Operand(index2.reg(), 0), object.reg());
   __ mov(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.)

   __ mov(tmp2.reg(), tmp1.reg());
-  __ RecordWriteHelper(tmp2.reg(), index1.reg(), object.reg());
-  __ RecordWriteHelper(tmp1.reg(), index2.reg(), object.reg());
+ __ RecordWriteHelper(tmp2.reg(), index1.reg(), object.reg(), kDontSaveFPRegs); + __ RecordWriteHelper(tmp1.reg(), index2.reg(), object.reg(), kDontSaveFPRegs);
   __ bind(&done);
-#endif

   deferred->BindExit();
   frame_->Push(Factory::undefined_value());
@@ -9659,22 +9657,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) {
       __ mov(receiver.reg(), Immediate(BitCast<int32_t>(kZapValue)));
       __ mov(value.reg(), Immediate(BitCast<int32_t>(kZapValue)));
       __ mov(scratch.reg(), Immediate(BitCast<int32_t>(kZapValue)));
     }
     __ bind(&skip_write_barrier);
-#else
-    // Store some dummy value to avoid short encoding of test instruction.
-    int delta_to_record_write = 0x0001;
-#endif
     value.Unuse();
     scratch.Unuse();
     receiver.Unuse();
@@ -9808,11 +9804,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();
@@ -9852,7 +9846,6 @@
     __ mov(tmp.reg(),
            FieldOperand(receiver.reg(), JSArray::kElementsOffset));

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
// 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.
@@ -9865,7 +9858,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
     // always fail so that we will hit the IC call in the deferred code
=======================================
--- /branches/experimental/gc/src/ia32/full-codegen-ia32.cc Wed Jan 5 05:52:13 2011 +++ /branches/experimental/gc/src/ia32/full-codegen-ia32.cc Wed Jan 5 06:17:18 2011
@@ -170,13 +170,11 @@
         // Store it in the context.
         int context_offset = Context::SlotOffset(slot->index());
         __ mov(Operand(esi, context_offset), eax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
         // Update the write barrier. This clobbers all involved
         // registers, so we have use a third register to avoid
         // clobbering esi.
         __ mov(ecx, esi);
-        __ RecordWrite(ecx, context_offset, eax, ebx);
-#endif
+        __ RecordWrite(ecx, context_offset, eax, ebx, kDontSaveFPRegs);
       }
     }
   }
@@ -603,13 +601,11 @@
   MemOperand location = EmitSlotSearch(dst, scratch1);
   __ mov(location, src);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   // Emit the write barrier code if the location is in the heap.
   if (dst->type() == Slot::CONTEXT) {
     int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
-    __ RecordWrite(scratch1, offset, src, scratch2);
-  }
-#endif
+    __ RecordWrite(scratch1, offset, src, scratch2, kDontSaveFPRegs);
+  }
 }


@@ -678,11 +674,9 @@
         } else if (function != NULL) {
           VisitForAccumulatorValue(function);
           __ mov(ContextOperand(esi, slot->index()), result_register());
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
           int offset = Context::SlotOffset(slot->index());
           __ mov(ebx, esi);
-          __ RecordWrite(ebx, offset, result_register(), ecx);
-#endif
+ __ RecordWrite(ebx, offset, result_register(), ecx, kDontSaveFPRegs);
         }
         break;

@@ -1452,10 +1446,8 @@
     int offset = FixedArray::kHeaderSize + (i * kPointerSize);
     __ mov(FieldOperand(ebx, offset), result_register());

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
     // Update the write barrier for the array store.
-    __ RecordWrite(ebx, offset, result_register(), ecx);
-#endif
+    __ RecordWrite(ebx, offset, result_register(), ecx, kDontSaveFPRegs);

     PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
   }
@@ -2024,13 +2016,11 @@
         // Perform the assignment and issue the write barrier.
         __ mov(target, eax);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
         // The value of the assignment is in eax.  RecordWrite clobbers its
         // register arguments.
         __ mov(edx, eax);
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
-        __ RecordWrite(ecx, offset, edx, ebx);
-#endif
+        __ RecordWrite(ecx, offset, edx, ebx, kDontSaveFPRegs);
         break;
       }

@@ -2906,7 +2896,7 @@
   VisitForAccumulatorValue(args->at(1));  // Load the value.
   __ pop(ebx);  // eax = value. ebx = object.

-  NearLabel done;
+  Label done;
   // If the object is a smi, return the value.
   __ test(ebx, Immediate(kSmiTagMask));
   __ j(zero, &done);
@@ -2918,12 +2908,10 @@
   // Store the value.
   __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   // Update the write barrier.  Save the value as it will be
   // overwritten by the write barrier code and is needed afterward.
   __ mov(edx, eax);
-  __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
-#endif
+  __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);

   __ bind(&done);
   context()->Plug(eax);
@@ -3206,16 +3194,14 @@
   __ mov(Operand(index_2, 0), object);
   __ mov(Operand(index_1, 0), temp);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   Label new_space;
   __ InNewSpace(elements, temp, equal, &new_space);

   __ mov(object, elements);
-  __ RecordWriteHelper(object, index_1, temp);
-  __ RecordWriteHelper(elements, index_2, temp);
+  __ RecordWriteHelper(object, index_1, temp, kDontSaveFPRegs);
+  __ RecordWriteHelper(elements, index_2, temp, kDontSaveFPRegs);

   __ bind(&new_space);
-#endif

   // We are done. Drop elements from the stack, and return undefined.
   __ add(Operand(esp), Immediate(3 * kPointerSize));
=======================================
--- /branches/experimental/gc/src/ia32/ic-ia32.cc       Wed Jan  5 05:52:13 2011
+++ /branches/experimental/gc/src/ia32/ic-ia32.cc       Wed Jan  5 06:17:18 2011
@@ -264,10 +264,8 @@
   __ mov(Operand(r0, 0), value);

   // Update write barrier. Make sure not to clobber the value.
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   __ mov(r1, value);
-  __ RecordWrite(elements, r0, r1);
-#endif
+  __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
 }


@@ -1027,11 +1025,9 @@
   // edi: FixedArray receiver->elements
   __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
   // Update write barrier for the elements array address.
   __ mov(edx, Operand(eax));
-  __ RecordWrite(edi, 0, edx, ecx);
-#endif
+  __ RecordWrite(edi, 0, edx, ecx, kDontSaveFPRegs);
   __ ret(0);
 }

=======================================
--- /branches/experimental/gc/src/ia32/lithium-codegen-ia32.cc Wed Jan 5 05:52:13 2011 +++ /branches/experimental/gc/src/ia32/lithium-codegen-ia32.cc Wed Jan 5 06:17:18 2011
@@ -2483,24 +2483,20 @@
   // Do the store.
   if (instr->is_in_object()) {
     __ mov(FieldOperand(object, offset), value);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
     if (instr->needs_write_barrier()) {
       Register temp = ToRegister(instr->temp());
       // Update the write barrier for the object for in-object properties.
-      __ RecordWrite(object, offset, value, temp);
-    }
-#endif
+      __ RecordWrite(object, offset, value, temp, kSaveFPRegs);
+    }
   } else {
     Register temp = ToRegister(instr->temp());
     __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
     __ mov(FieldOperand(temp, offset), value);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
     if (instr->needs_write_barrier()) {
       // Update the write barrier for the properties array.
       // object is used as a scratch register.
-      __ RecordWrite(temp, offset, value, object);
-    }
-#endif
+      __ RecordWrite(temp, offset, value, object, kSaveFPRegs);
+    }
   }
 }

@@ -2538,14 +2534,12 @@
            value);
   }

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
// Update the write barrier unless we're certain that we're storing a smi.
   if (instr->hydrogen()->NeedsWriteBarrier()) {
     // Compute address of modified element and store it into key register.
__ lea(key, FieldOperand(elements, key, times_4, FixedArray::kHeaderSize));
-    __ RecordWrite(elements, key, value);
-  }
-#endif
+    __ RecordWrite(elements, key, value, kSaveFPRegs);
+  }
 }


=======================================
--- /branches/experimental/gc/src/ia32/macro-assembler-ia32.cc Tue Dec 21 04:32:46 2010 +++ /branches/experimental/gc/src/ia32/macro-assembler-ia32.cc Wed Jan 5 06:17:18 2011
@@ -48,10 +48,10 @@
       code_object_(Heap::undefined_value()) {
 }

-#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.
     Label not_in_new_space;
@@ -60,24 +60,32 @@
     bind(&not_in_new_space);
   }

-  // Compute the page start address from the heap object pointer, and reuse
-  // the 'object' register for it.
-  and_(object, ~Page::kPageAlignmentMask);
-
- // Compute number of region covering addr. See Page::GetRegionNumberForAddress
-  // method for more details.
-  and_(addr, Page::kPageAlignmentMask);
-  shr(addr, Page::kRegionSizeLog2);
-
-  // Set dirty mark for region.
-  bts(Operand(object, Page::kDirtyFlagOffset), addr);
+  // Load write buffer top.
+  ExternalReference write_buffer = ExternalReference::write_buffer_top();
+  mov(scratch, Operand::StaticVariable(write_buffer));
+  // Store pointer to buffer.
+  mov(Operand(scratch, 0), addr);
+  // Increment buffer top.
+  add(Operand(scratch), Immediate(kPointerSize));
+  // Write back new top of buffer.
+  mov(Operand::StaticVariable(write_buffer), scratch);
+  // Call stub on end of buffer.
+  NearLabel no_overflow;
+  // Check for end of buffer.
+  test(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 scratch) {
+                                 Register scratch,
+                                 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.
@@ -112,7 +120,7 @@
     lea(dst, Operand(object, dst, times_half_pointer_size,
                      FixedArray::kHeaderSize - kHeapObjectTag));
   }
-  RecordWriteHelper(object, dst, value);
+  RecordWriteHelper(object, dst, value, save_fp);

   bind(&done);

@@ -128,7 +136,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.
@@ -145,7 +154,7 @@

   InNewSpace(object, value, equal, &done);

-  RecordWriteHelper(object, address, value);
+  RecordWriteHelper(object, address, value, save_fp);

   bind(&done);

@@ -157,7 +166,7 @@
     mov(value, Immediate(BitCast<int32_t>(kZapValue)));
   }
 }
-#endif
+

 #ifdef ENABLE_DEBUGGER_SUPPORT
 void MacroAssembler::DebugBreak() {
@@ -382,10 +391,22 @@
   // Optionally restore all XMM registers.
   if (save_doubles) {
     CpuFeatures::Scope scope(SSE2);
-    int offset = -2 * kPointerSize;
-    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
-      XMMRegister reg = XMMRegister::from_code(i);
-      movdbl(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
+    if (save_doubles) {
+      int offset = -2 * kPointerSize;
+      for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
+        XMMRegister reg = XMMRegister::from_code(i);
+        movdbl(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
+      }
+    } else if (FLAG_debug_code) {
+ // Zap all fp registers on a runtime call if we were not asked to preserve
+      // them.
+      push(eax);
+      mov(eax, Factory::nan_value());
+      for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
+        XMMRegister reg = XMMRegister::from_code(i);
+        movdbl(reg, FieldOperand(eax, HeapNumber::kValueOffset));
+      }
+      pop(eax);
     }
   }

@@ -1092,8 +1113,7 @@
   Runtime::Function* function = Runtime::FunctionForId(id);
   Set(eax, Immediate(function->nargs));
   mov(ebx, Immediate(ExternalReference(function)));
-  CEntryStub ces(1);
-  ces.SaveDoubles();
+  CEntryStub ces(1, kSaveFPRegs);
   CallStub(&ces);
 }

=======================================
--- /branches/experimental/gc/src/ia32/macro-assembler-ia32.h Tue Dec 21 04:32:46 2010 +++ /branches/experimental/gc/src/ia32/macro-assembler-ia32.h Wed Jan 5 06:17:18 2011
@@ -61,13 +61,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.
   // scratch can be object itself, but it will be clobbered.
@@ -87,7 +87,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
@@ -96,8 +97,8 @@
   // write barrier if the value is a smi.
   void RecordWrite(Register object,
                    Register address,
-                   Register value);
-#endif
+                   Register value,
+                   SaveFPRegsMode save_fp);

 #ifdef ENABLE_DEBUGGER_SUPPORT
// ---------------------------------------------------------------------------
@@ -661,7 +662,6 @@
 };


-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
 template <typename LabelType>
 void MacroAssembler::InNewSpace(Register object,
                                 Register scratch,
@@ -685,7 +685,6 @@
     j(cc, branch);
   }
 }
-#endif


// The code patcher is used to patch (typically) small parts of code e.g. for
=======================================
--- /branches/experimental/gc/src/ia32/stub-cache-ia32.cc Wed Jan 5 05:52:13 2011 +++ /branches/experimental/gc/src/ia32/stub-cache-ia32.cc Wed Jan 5 06:17:18 2011
@@ -818,12 +818,10 @@
     int offset = object->map()->instance_size() + (index * kPointerSize);
     __ mov(FieldOperand(receiver_reg, offset), eax);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
     // Update the write barrier for the array address.
     // Pass the value being stored in the now unused name_reg.
     __ mov(name_reg, Operand(eax));
-    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
-#endif
+ __ RecordWrite(receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs);
   } else {
     // Write to the properties array.
     int offset = index * kPointerSize + FixedArray::kHeaderSize;
@@ -831,12 +829,10 @@
__ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
     __ mov(FieldOperand(scratch, offset), eax);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
     // Update the write barrier for the array address.
     // Pass the value being stored in the now unused name_reg.
     __ mov(name_reg, Operand(eax));
-    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
-#endif
+ __ RecordWrite(scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs);
   }

   // Return the value (register eax).
@@ -1483,9 +1479,7 @@

     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

       // Get the array's length into eax and calculate new length.
       __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
@@ -1510,23 +1504,19 @@
       __ mov(ecx, Operand(esp, argc * kPointerSize));
       __ mov(Operand(edx, 0), ecx);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
       // Check if value is a smi.
       __ test(ecx, Immediate(kSmiTagMask));
       __ j(not_zero, &with_write_barrier);
-#endif

       __ bind(&exit);
       __ ret((argc + 1) * kPointerSize);

-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
       __ bind(&with_write_barrier);

       __ InNewSpace(ebx, ecx, equal, &exit);

-      __ RecordWriteHelper(ebx, edx, ecx);
+      __ RecordWriteHelper(ebx, edx, ecx, kDontSaveFPRegs);
       __ ret((argc + 1) * kPointerSize);
-#endif

       __ bind(&attempt_to_grow_elements);
       if (!FLAG_inline_new) {
@@ -2695,9 +2685,7 @@
   // the value in register eax.
   __ mov(edx, Operand(eax));
   __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
-#ifdef ENABLE_CARDMARKING_WRITE_BARRIER
-  __ RecordWrite(edi, 0, edx, ecx);
-#endif
+  __ RecordWrite(edi, 0, edx, ecx, kDontSaveFPRegs);

   // Done.
   __ ret(0);
=======================================
--- /branches/experimental/gc/src/runtime.cc    Tue Dec 21 04:32:46 2010
+++ /branches/experimental/gc/src/runtime.cc    Wed Jan  5 06:17:18 2011
@@ -5398,6 +5398,12 @@
   }
   return Heap::nan_value();
 }
+
+
+static MaybeObject* Runtime_WriteBufferOverflow(Arguments args) {
+  WriteBuffer::Compact();
+  return Heap::undefined_value();
+}


 static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
=======================================
--- /branches/experimental/gc/src/runtime.h     Tue Dec 21 04:32:46 2010
+++ /branches/experimental/gc/src/runtime.h     Wed Jan  5 06:17:18 2011
@@ -82,10 +82,11 @@
   F(LazyRecompile, 1, 1) \
   F(NotifyDeoptimized, 1, 1) \
   F(NotifyOSR, 0, 1) \
-  F(DeoptimizeFunction, 1, 1)             \
+  F(DeoptimizeFunction, 1, 1) \
   F(CompileForOnStackReplacement, 1, 1) \
   F(SetNewFunctionAttributes, 1, 1) \
   F(AllocateInNewSpace, 1, 1) \
+  F(WriteBufferOverflow, 0, 1) \
   \
   /* Array join support */ \
   F(PushIfAbsent, 2, 1) \
=======================================
--- /branches/experimental/gc/src/serialize.cc  Wed Dec  8 06:32:40 2010
+++ /branches/experimental/gc/src/serialize.cc  Wed Jan  5 06:17:18 2011
@@ -498,6 +498,10 @@
       UNCLASSIFIED,
       39,
       "power_double_int_function");
+  Add(ExternalReference::write_buffer_top().address(),
+      UNCLASSIFIED,
+      40,
+      "write_buffer_top");
 }


=======================================
--- /branches/experimental/gc/src/write-buffer.cc       Thu Dec 16 12:15:51 2010
+++ /branches/experimental/gc/src/write-buffer.cc       Wed Jan  5 06:17:18 2011
@@ -83,6 +83,7 @@
   memset(reinterpret_cast<void*>(hash_map_2_),
          0,
          sizeof(uintptr_t) * kHashMapLength);
+  ASSERT(top_ <= limit_);
   Address* stop = top_;
   top_ = start_;
   // Goes through the addresses in the write buffer attempting to remove
=======================================
--- /branches/experimental/gc/src/write-buffer.h        Thu Dec 16 12:15:51 2010
+++ /branches/experimental/gc/src/write-buffer.h        Wed Jan  5 06:17:18 2011
@@ -61,6 +61,8 @@
   static const int kHashMapLengthLog2 = 12;
   static const int kHashMapLength = 1 << kHashMapLengthLog2;

+  static void Compact();
+
  private:
   static Address* top_;
   static Address* start_;
@@ -68,8 +70,6 @@
   static VirtualMemory* virtual_memory_;
   static uintptr_t* hash_map_1_;
   static uintptr_t* hash_map_2_;
-
-  static void Compact();
 };

 } }  // namespace v8::internal
=======================================
--- /branches/experimental/gc/test/cctest/test-alloc.cc Thu Dec 23 08:04:56 2010 +++ /branches/experimental/gc/test/cctest/test-alloc.cc Wed Jan 5 06:17:18 2011
@@ -192,7 +192,7 @@
     if (current_allocated < code_range_size / 10) {
       // Allocate a block.
// Geometrically distributed sizes, greater than Page::kMaxHeapObjectSize. - // TODO (gc) instead of using 3 use some contant based on code_range_size + // TODO(gc): instead of using 3 use some contant based on code_range_size
       // kMaxHeapObjectSize.
size_t requested = (Page::kMaxHeapObjectSize << (Pseudorandom() % 3)) +
            Pseudorandom() % 5000 + 1;

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to