// Enter a construct frame.
__ EnterConstructFrame();
- // Preserve the two incoming parameters
+ // Preserve the two incoming parameters on the stack.
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
- __ push(r0); // smi-tagged arguments count
- __ push(r1); // constructor function
+ __ push(r0); // Smi-tagged arguments count.
+ __ push(r1); // Constructor function.
+
+ // Use r7 for holding undefined which is used in several places below.
+ __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
+
+ // Try to allocate the object without transitioning into C code. If any of the
+ // preconditions is not met, the code bails out to the runtime call.
+ Label rt_call, allocated;
+ if (FLAG_inline_new) {
+ Label undo_allocation;
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ ExternalReference debug_step_in_fp =
+ ExternalReference::debug_step_in_fp_address();
+ __ mov(r2, Operand(debug_step_in_fp));
+ __ ldr(r2, MemOperand(r2));
+ __ tst(r2, r2);
+ __ b(nz, &rt_call);
+#endif
+
+ // Load the initial map and verify that it is in fact a map.
+ // r1: constructor function
+ // r7: undefined
+ __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
+ __ tst(r2, Operand(kSmiTagMask));
+ __ b(eq, &rt_call);
+ __ CompareObjectType(r2, r3, r4, MAP_TYPE);
+ __ b(ne, &rt_call);
+
+ // Check that the constructor is not constructing a JSFunction (see comments
+ // in Runtime_NewObject in runtime.cc). In which case the initial map's
+ // instance type would be JS_FUNCTION_TYPE.
+ // r1: constructor function
+ // r2: initial map
+ // r7: undefined
+ __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE);
+ __ b(eq, &rt_call);
+
+ // Now allocate the JSObject on the heap.
+ // r1: constructor function
+ // r2: initial map
+ // r7: undefined
+ __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
+ // Make sure that the maximum heap object size will never cause us
+ // problem here, because it is always greater than the maximum
+ // instance size that can be represented in a byte.
+ ASSERT(Heap::MaxObjectSizeInPagedSpace() >= JSObject::kMaxInstanceSize);
+ __ AllocateObjectInNewSpace(r3, r4, r5, r6, &rt_call, false);
+
+ // Allocated the JSObject, now initialize the fields. Map is set to initial
+ // map and properties and elements are set to empty fixed array.
+ // r1: constructor function
+ // r2: initial map
+ // r3: object size
+ // r4: JSObject (not tagged)
+ // r7: undefined
+ __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
+ __ mov(r5, r4);
+ ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
+ __ str(r2, MemOperand(r5, kPointerSize, PostIndex));
+ ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
+ __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
+ ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
+ __ str(r6, MemOperand(r5, kPointerSize, PostIndex));
+
+ // Fill all the in-object properties with undefined.
+ // r1: constructor function
+ // r2: initial map
+ // r3: object size (in words)
+ // r4: JSObject (not tagged)
+ // r5: First in-object property of JSObject (not tagged)
+ // r7: undefined
+ __ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of object.
+ ASSERT_EQ(12, JSObject::kHeaderSize);
+ { Label loop, entry;
+ __ b(&entry);
+ __ bind(&loop);
+ __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
+ __ bind(&entry);
+ __ cmp(r5, Operand(r6));
+ __ b(lt, &loop);
+ }
+
+ // 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.
+ __ add(r4, r4, Operand(kHeapObjectTag));
+
+ // Check if a non-empty properties array is needed. Continue with allocated
+ // object if not fall through to runtime call if it is.
+ // r1: constructor function
+ // r2: initial map
+ // r4: JSObject
+ // r5: start of next object (not tagged)
+ // r7: undefined
+ __ ldrb(r3, FieldMemOperand(r2, Map::kUnusedPropertyFieldsOffset));
+ // The field instance sizes contains both pre-allocated property fields and
+ // in-object properties.
+ __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
+ __ and_(r6,
+ r0,
+ Operand(0x000000FF << Map::kPreAllocatedPropertyFieldsByte * 8));
+ __ add(r3, r3, Operand(r6, LSR, Map::kPreAllocatedPropertyFieldsByte * 8));
+ __ and_(r6, r0, Operand(0x000000FF << Map::kInObjectPropertiesByte * 8));
+ __ sub(r3, r3, Operand(r6, LSR, Map::kInObjectPropertiesByte * 8), SetCC);
+
+ // Done if no extra properties are to be allocated.
+ __ b(eq, &allocated);
+ __ Assert(al, "Property allocation count failed.");
+
+ // Undo the setting of the new top so that the heap is verifiable. For
+ // example, the map's unused properties potentially do not match the
+ // allocated objects unused properties.
+ // r4: JSObject (previous new top)
+ __ bind(&undo_allocation);
+ __ UndoAllocationInNewSpace(r4, r5);
+ }
- // Allocate the new receiver object.
+ // Allocate the new receiver object using the runtime call.
+ __ bind(&rt_call);
__ push(r1); // argument for Runtime_NewObject
__ CallRuntime(Runtime::kNewObject, 1);
- __ push(r0); // save the receiver
+ __ mov(r4, r0);
+
+ // Receiver for constructor call allocated.
+ // r4: JSObject
+ __ bind(&allocated);
+ __ push(r4);
// Push the function and the allocated receiver from the stack.
// sp[0]: receiver (newly allocated object)
// sp[1]: constructor function
// sp[2]: number of arguments (smi-tagged)
__ ldr(r1, MemOperand(sp, kPointerSize));
- __ push(r1); // function
- __ push(r0); // receiver
+ __ push(r1); // Constructor function.
+ __ push(r4); // Receiver.
// Reload the number of arguments from the stack.
// r1: constructor function
__ LeaveConstructFrame();
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
__ add(sp, sp, Operand(kPointerSize));
+ __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
__ Jump(lr);
}
ExternalReference::new_space_allocation_limit_address();
mov(scratch2, Operand(new_space_allocation_limit));
ldr(scratch2, MemOperand(scratch2));
- add(result, result, Operand(object_size));
+ add(result, result, Operand(object_size * kPointerSize));
cmp(result, Operand(scratch2));
b(hi, gc_required);
// Tag and adjust back to start of new object.
if (tag_allocated_object) {
- sub(result, result, Operand(object_size - kHeapObjectTag));
+ sub(result, result, Operand((object_size * kPointerSize) -
+ kHeapObjectTag));
} else {
- sub(result, result, Operand(object_size));
+ sub(result, result, Operand(object_size * kPointerSize));
}
}
+void MacroAssembler::AllocateObjectInNewSpace(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ bool tag_allocated_object) {
+ ASSERT(!result.is(scratch1));
+ ASSERT(!scratch1.is(scratch2));
+
+ // Load address of new object into result and allocation top address into
+ // scratch1.
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address();
+ mov(scratch1, Operand(new_space_allocation_top));
+ ldr(result, MemOperand(scratch1));
+
+ // Calculate new top and bail out if new space is exhausted. Use result
+ // to calculate the new top. Object size is in words so a shift is required to
+ // get the number of bytes
+ ExternalReference new_space_allocation_limit =
+ ExternalReference::new_space_allocation_limit_address();
+ mov(scratch2, Operand(new_space_allocation_limit));
+ ldr(scratch2, MemOperand(scratch2));
+ add(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+
+ cmp(result, Operand(scratch2));
+ b(hi, gc_required);
+
+ // Update allocation top. result temporarily holds the new top,
+ str(result, MemOperand(scratch1));
+
+ // Tag and adjust back to start of new object.
+ if (tag_allocated_object) {
+ sub(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+ add(result, result, Operand(kHeapObjectTag));
+ } else {
+ sub(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+ }
+}
+
+
+void MacroAssembler::UndoAllocationInNewSpace(Register object,
+ Register scratch) {
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address();
+
+ // Make sure the object has no tag before resetting top.
+ and_(object, object, Operand(~kHeapObjectTagMask));
+#ifdef DEBUG
+ // Check that the object un-allocated is below the current top.
+ mov(scratch, Operand(new_space_allocation_top));
+ ldr(scratch, MemOperand(scratch));
+ cmp(object, scratch);
+ Check(lt, "Undo allocation of non allocated memory");
+#endif
+ // Write the address of the object to un-allocate as the current top.
+ mov(scratch, Operand(new_space_allocation_top));
+ str(object, MemOperand(scratch));
+}
+
+
void MacroAssembler::CompareObjectType(Register function,
Register map,
Register type_reg,
InstanceType type) {
ldr(map, FieldMemOperand(function, HeapObject::kMapOffset));
+ CompareInstanceType(map, type_reg, type);
+}
+
+
+void MacroAssembler::CompareInstanceType(Register map,
+ Register type_reg,
+ InstanceType type) {
ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
cmp(type_reg, Operand(type));
}
// ---------------------------------------------------------------------------
// 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. If the flag tag_allocated_object is true the result is tagged as
- // as a heap object.
+ // Allocate an object in new space. The object_size is specified in words (not
+ // bytes). If the new space is exhausted control continues at the gc_required
+ // label. The allocated object is returned in result. If the flag
+ // tag_allocated_object is true the result is tagged as as a heap object.
void AllocateObjectInNewSpace(int object_size,
Register result,
Register scratch1,
Register scratch2,
Label* gc_required,
bool tag_allocated_object);
+ void AllocateObjectInNewSpace(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ bool tag_allocated_object);
+
+ // Undo allocation in new space. The object passed and objects allocated after
+ // it will no longer be allocated. The caller must make sure that no pointers
+ // are left to the object(s) no longer allocated as they would be invalid when
+ // allocation is undone.
+ void UndoAllocationInNewSpace(Register object, Register scratch);
// ---------------------------------------------------------------------------
// Support functions.
// It leaves the map in the map register (unless the type_reg and map register
// are the same register). It leaves the heap object in the heap_object
// register unless the heap_object register is the same register as one of the
- // other // registers.
+ // other registers.
void CompareObjectType(Register heap_object,
Register map,
Register type_reg,
InstanceType type);
+ // Compare instance type in a map. map contains a valid map object whose
+ // object type should be compared with the given type. This both
+ // sets the flags and leaves the object type in the type_reg register. It
+ // leaves the heap object in the heap_object register unless the heap_object
+ // register is the same register as type_reg.
+ void CompareInstanceType(Register map,
+ Register type_reg,
+ InstanceType type);
+
inline void BranchOnSmi(Register value, Label* smi_label) {
tst(value, Operand(kSmiTagMask));
b(eq, smi_label);