Add allocation support to x64 macro assembler.
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 28 Aug 2009 06:18:36 +0000 (06:18 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 28 Aug 2009 06:18:36 +0000 (06:18 +0000)
Factored out the allocation in new space from assembler code into the macro assembler for x64 as was recently done for ia32.

Added set property svn:eol-style to native for all x64 files.
Review URL: http://codereview.chromium.org/173568

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2778 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ia32/builtins-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/x64/builtins-x64.cc
src/x64/codegen-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index bc7b7c7..55dc92d 100644 (file)
@@ -158,10 +158,10 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
       __ j(less, &loop);
     }
 
-    // Mostly done with the JSObject. Add the heap tag and store the new top, so
-    // that we can continue and jump into the continuation code at any time from
-    // now on. Any failures need to undo the setting of the new top, so that the
-    // heap is in a consistent state and verifiable.
+    // Add the object tag to make the JSObject real, so that we can continue and
+    // jump into the continuation code at any time from now on. Any failures
+    // need to undo the allocation, so that the heap is in a consistent state
+    // and verifiable.
     // eax: initial map
     // ebx: JSObject
     // edi: start of next object
index 9932c93..754b74a 100644 (file)
@@ -669,14 +669,14 @@ void MacroAssembler::AllocateObjectInNewSpace(
   ASSERT(!result.is(result_end));
 
   // Load address of new object into result.
-  ExternalReference new_space_allocation_limit =
-      ExternalReference::new_space_allocation_limit_address();
   LoadAllocationTopHelper(result,
                           result_end,
                           scratch,
                           result_contains_top_on_entry);
 
   // Calculate new top and bail out if new space is exhausted.
+  ExternalReference new_space_allocation_limit =
+      ExternalReference::new_space_allocation_limit_address();
   lea(result_end, Operand(result, object_size));
   cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
   j(above, gc_required, not_taken);
index 6d10ee5..882b32d 100644 (file)
@@ -542,16 +542,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
     // problem here, because it is always greater than the maximum
     // instance size that can be represented in a byte.
     ASSERT(Heap::MaxObjectSizeInPagedSpace() >= (1 << kBitsPerByte));
-    ExternalReference new_space_allocation_top =
-        ExternalReference::new_space_allocation_top_address();
-    __ movq(kScratchRegister, new_space_allocation_top);
-    __ movq(rbx, Operand(kScratchRegister, 0));
-    __ addq(rdi, rbx);  // Calculate new top
-    ExternalReference new_space_allocation_limit =
-        ExternalReference::new_space_allocation_limit_address();
-    __ movq(kScratchRegister, new_space_allocation_limit);
-    __ cmpq(rdi, Operand(kScratchRegister, 0));
-    __ j(above_equal, &rt_call);
+    __ AllocateObjectInNewSpace(rdi, rbx, rdi, no_reg, &rt_call, false);
     // Allocated the JSObject, now initialize the fields.
     // rax: initial map
     // rbx: JSObject (not HeapObject tagged - the actual address).
@@ -576,16 +567,14 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
       __ j(less, &loop);
     }
 
-    // Mostly done with the JSObject. Add the heap tag and store the new top, so
-    // that we can continue and jump into the continuation code at any time from
-    // now on. Any failures need to undo the setting of the new top, so that the
-    // heap is in a consistent state and verifiable.
+    // Add the object tag to make the JSObject real, so that we can continue and
+    // jump into the continuation code at any time from now on. Any failures
+    // need to undo the allocation, so that the heap is in a consistent state
+    // and verifiable.
     // rax: initial map
     // rbx: JSObject
     // rdi: start of next object
     __ or_(rbx, Immediate(kHeapObjectTag));
-    __ movq(kScratchRegister, new_space_allocation_top);
-    __ movq(Operand(kScratchRegister, 0), rdi);
 
     // Check if a non-empty properties array is needed.
     // Allocate and initialize a FixedArray if it is.
@@ -610,11 +599,14 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
     // rdx: number of elements in properties array
     ASSERT(Heap::MaxObjectSizeInPagedSpace() >
            (FixedArray::kHeaderSize + 255*kPointerSize));
-    __ lea(rax, Operand(rdi, rdx, times_pointer_size, FixedArray::kHeaderSize));
-    __ movq(kScratchRegister, new_space_allocation_limit);
-    __ cmpq(rax, Operand(kScratchRegister, 0));
-    __ j(above_equal, &undo_allocation);
-    __ store_rax(new_space_allocation_top);
+    __ AllocateObjectInNewSpace(FixedArray::kHeaderSize,
+                                times_pointer_size,
+                                rdx,
+                                rdi,
+                                rax,
+                                no_reg,
+                                &undo_allocation,
+                                true);
 
     // Initialize the FixedArray.
     // rbx: JSObject
@@ -659,9 +651,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
     // allocated objects unused properties.
     // rbx: JSObject (previous new top)
     __ bind(&undo_allocation);
-    __ xor_(rbx, Immediate(kHeapObjectTag));  // clear the heap tag
-    __ movq(kScratchRegister, new_space_allocation_top);
-    __ movq(Operand(kScratchRegister, 0), rbx);
+    __ UndoAllocationInNewSpace(rbx);
   }
 
   // Allocate the new receiver object using the runtime call.
index 7c8edc9..f915a0c 100644 (file)
@@ -7324,24 +7324,20 @@ void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
                                              Label* need_gc,
                                              Register scratch,
                                              Register result) {
-  ExternalReference allocation_top =
-      ExternalReference::new_space_allocation_top_address();
-  ExternalReference allocation_limit =
-      ExternalReference::new_space_allocation_limit_address();
-  __ movq(scratch, allocation_top);  // scratch: address of allocation top.
-  __ movq(result, Operand(scratch, 0));
-  __ addq(result, Immediate(HeapNumber::kSize));  // New top.
-  __ movq(kScratchRegister, allocation_limit);
-  __ cmpq(result, Operand(kScratchRegister, 0));
-  __ j(above, need_gc);
-
-  __ movq(Operand(scratch, 0), result);  // store new top
-  __ addq(result, Immediate(kHeapObjectTag - HeapNumber::kSize));
+  // Allocate heap number in new space.
+  __ AllocateObjectInNewSpace(HeapNumber::kSize,
+                              result,
+                              scratch,
+                              no_reg,
+                              need_gc,
+                              false);
+
+  // Set the map and tag the result.
+  __ addq(result, Immediate(kHeapObjectTag));
   __ movq(kScratchRegister,
           Factory::heap_number_map(),
           RelocInfo::EMBEDDED_OBJECT);
   __ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
-  // Tag old top and use as result.
 }
 
 
index 157ec2e..10d4503 100644 (file)
@@ -1204,4 +1204,156 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 }
 
 
+void MacroAssembler::LoadAllocationTopHelper(
+    Register result,
+    Register result_end,
+    Register scratch,
+    bool result_contains_top_on_entry) {
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address();
+
+  // Just return if allocation top is already known.
+  if (result_contains_top_on_entry) {
+    // No use of scratch if allocation top is provided.
+    ASSERT(scratch.is(no_reg));
+    return;
+  }
+
+  // Move address of new object to result. Use scratch register if available.
+  if (scratch.is(no_reg)) {
+    movq(kScratchRegister, new_space_allocation_top);
+    movq(result, Operand(kScratchRegister, 0));
+  } else {
+    ASSERT(!scratch.is(result_end));
+    movq(scratch, new_space_allocation_top);
+    movq(result, Operand(scratch, 0));
+  }
+}
+
+
+void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
+                                               Register scratch) {
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address();
+
+  // Update new top.
+  if (result_end.is(rax)) {
+    // rax can be stored directly to a memory location.
+    store_rax(new_space_allocation_top);
+  } else {
+    // Register required - use scratch provided if available.
+    if (scratch.is(no_reg)) {
+      movq(kScratchRegister, new_space_allocation_top);
+      movq(Operand(kScratchRegister, 0), result_end);
+    } else {
+      movq(Operand(scratch, 0), result_end);
+    }
+  }
+}
+
+
+void MacroAssembler::AllocateObjectInNewSpace(
+    int object_size,
+    Register result,
+    Register result_end,
+    Register scratch,
+    Label* gc_required,
+    bool result_contains_top_on_entry) {
+  ASSERT(!result.is(result_end));
+
+  // Load address of new object into result.
+  LoadAllocationTopHelper(result,
+                          result_end,
+                          scratch,
+                          result_contains_top_on_entry);
+
+  // Calculate new top and bail out if new space is exhausted.
+  ExternalReference new_space_allocation_limit =
+      ExternalReference::new_space_allocation_limit_address();
+  lea(result_end, Operand(result, object_size));
+  movq(kScratchRegister, new_space_allocation_limit);
+  cmpq(result_end, Operand(kScratchRegister, 0));
+  j(above, gc_required);
+
+  // Update allocation top.
+  UpdateAllocationTopHelper(result_end, scratch);
+}
+
+
+void MacroAssembler::AllocateObjectInNewSpace(
+    int header_size,
+    ScaleFactor element_size,
+    Register element_count,
+    Register result,
+    Register result_end,
+    Register scratch,
+    Label* gc_required,
+    bool result_contains_top_on_entry) {
+  ASSERT(!result.is(result_end));
+
+  // Load address of new object into result.
+  LoadAllocationTopHelper(result,
+                          result_end,
+                          scratch,
+                          result_contains_top_on_entry);
+
+  // Calculate new top and bail out if new space is exhausted.
+  ExternalReference new_space_allocation_limit =
+      ExternalReference::new_space_allocation_limit_address();
+  lea(result_end, Operand(result, element_count, element_size, header_size));
+  movq(kScratchRegister, new_space_allocation_limit);
+  cmpq(result_end, Operand(kScratchRegister, 0));
+  j(above, gc_required);
+
+  // Update allocation top.
+  UpdateAllocationTopHelper(result_end, scratch);
+}
+
+
+void MacroAssembler::AllocateObjectInNewSpace(
+    Register object_size,
+    Register result,
+    Register result_end,
+    Register scratch,
+    Label* gc_required,
+    bool result_contains_top_on_entry) {
+
+  // Load address of new object into result.
+  LoadAllocationTopHelper(result,
+                          result_end,
+                          scratch,
+                          result_contains_top_on_entry);
+
+
+  // Calculate new top and bail out if new space is exhausted.
+  ExternalReference new_space_allocation_limit =
+      ExternalReference::new_space_allocation_limit_address();
+  if (!object_size.is(result_end)) {
+    movq(result_end, object_size);
+  }
+  addq(result_end, result);
+  movq(kScratchRegister, new_space_allocation_limit);
+  cmpq(result_end, Operand(kScratchRegister, 0));
+  j(above, gc_required);
+
+  // Update allocation top.
+  UpdateAllocationTopHelper(result_end, scratch);
+}
+
+
+void MacroAssembler::UndoAllocationInNewSpace(Register object) {
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address();
+
+  // Make sure the object has no tag before resetting top.
+  and_(object, Immediate(~kHeapObjectTagMask));
+  movq(kScratchRegister, new_space_allocation_top);
+#ifdef DEBUG
+  cmpq(object, Operand(kScratchRegister, 0));
+  Check(below, "Undo allocation of non allocated memory");
+#endif
+  movq(Operand(kScratchRegister, 0), object);
+}
+
+
 } }  // namespace v8::internal
index cba55eb..31135d9 100644 (file)
@@ -223,6 +223,48 @@ class MacroAssembler: public Assembler {
 
 
   // ---------------------------------------------------------------------------
+  // Allocation support
+
+  // Allocate an object in new space. If the new space is exhausted control
+  // continues at the gc_required label. The allocated object is returned in
+  // result and end of the new object is returned in result_end. The register
+  // scratch can be passed as no_reg in which case an additional object
+  // reference will be added to the reloc info. The returned pointers in result
+  // and result_end have not yet been tagged as heap objects. If
+  // result_contains_top_on_entry is true the content of result is known to be
+  // the allocation top on entry (could be result_end from a previous call to
+  // AllocateObjectInNewSpace). If result_contains_top_on_entry is true scratch
+  // should be no_reg as it is never used.
+  void AllocateObjectInNewSpace(int object_size,
+                                Register result,
+                                Register result_end,
+                                Register scratch,
+                                Label* gc_required,
+                                bool result_contains_top_on_entry);
+
+  void AllocateObjectInNewSpace(int header_size,
+                                ScaleFactor element_size,
+                                Register element_count,
+                                Register result,
+                                Register result_end,
+                                Register scratch,
+                                Label* gc_required,
+                                bool result_contains_top_on_entry);
+
+  void AllocateObjectInNewSpace(Register object_size,
+                                Register result,
+                                Register result_end,
+                                Register scratch,
+                                Label* gc_required,
+                                bool result_contains_top_on_entry);
+
+  // Undo allocation in new space. The object passed and objects allocated after
+  // it will no longer be allocated. Make sure that no pointers are left to the
+  // object(s) no longer allocated as they would be invalid when allocation is
+  // un-done.
+  void UndoAllocationInNewSpace(Register object);
+
+  // ---------------------------------------------------------------------------
   // Support functions.
 
   // Check if result is zero and op is negative.
@@ -341,6 +383,13 @@ class MacroAssembler: public Assembler {
   // Activation support.
   void EnterFrame(StackFrame::Type type);
   void LeaveFrame(StackFrame::Type type);
+
+  // Allocation support helpers.
+  void LoadAllocationTopHelper(Register result,
+                               Register result_end,
+                               Register scratch,
+                               bool result_contains_top_on_entry);
+  void UpdateAllocationTopHelper(Register result_end, Register scratch);
 };