__ 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
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);
// 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).
__ 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.
// 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
// 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.
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.
}
}
+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
// ---------------------------------------------------------------------------
+ // 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.
// 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);
};