| Index: src/x64/builtins-x64.cc
|
| ===================================================================
|
| --- src/x64/builtins-x64.cc (revision 2646)
|
| +++ src/x64/builtins-x64.cc (working copy)
|
| @@ -503,13 +503,160 @@
|
| // 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;
|
| + // TODO(X64): Enable debugger support, using debug_step_in_fp.
|
|
|
| - // TODO(x64): Implement inlined allocation.
|
| + // Verified that the constructor is a JSFunction.
|
| + // Load the initial map and verify that it is in fact a map.
|
| + // rdi: constructor
|
| + __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
|
| + // Will both indicate a NULL and a Smi
|
| + __ testl(rax, Immediate(kSmiTagMask));
|
| + __ j(zero, &rt_call);
|
| + // rdi: constructor
|
| + // rax: initial map (if proven valid below)
|
| + __ CmpObjectType(rax, MAP_TYPE, rbx);
|
| + __ j(not_equal, &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.
|
| + // rdi: constructor
|
| + // rax: initial map
|
| + __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
|
| + __ j(equal, &rt_call);
|
| +
|
| + // Now allocate the JSObject on the heap.
|
| + __ movzxbq(rdi, FieldOperand(rax, Map::kInstanceSizeOffset));
|
| + __ shl(rdi, Immediate(kPointerSizeLog2));
|
| + // rdi: size of new object
|
| + // 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() >= (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);
|
| + // Allocated the JSObject, now initialize the fields.
|
| + // rax: initial map
|
| + // rbx: JSObject (not HeapObject tagged - the actual address).
|
| + // rdi: start of next object
|
| + __ movq(Operand(rbx, JSObject::kMapOffset), rax);
|
| + __ Move(rcx, Factory::empty_fixed_array());
|
| + __ movq(Operand(rbx, JSObject::kPropertiesOffset), rcx);
|
| + __ movq(Operand(rbx, JSObject::kElementsOffset), rcx);
|
| + // Set extra fields in the newly allocated object.
|
| + // rax: initial map
|
| + // rbx: JSObject
|
| + // rdi: start of next object
|
| + { Label loop, entry;
|
| + __ Move(rdx, Factory::undefined_value());
|
| + __ lea(rcx, Operand(rbx, JSObject::kHeaderSize));
|
| + __ jmp(&entry);
|
| + __ bind(&loop);
|
| + __ movq(Operand(rcx, 0), rdx);
|
| + __ addq(rcx, Immediate(kPointerSize));
|
| + __ bind(&entry);
|
| + __ cmpq(rcx, rdi);
|
| + __ 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.
|
| + // 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.
|
| + // rax: initial map
|
| + // rbx: JSObject
|
| + // rdi: start of next object
|
| + __ movzxbq(rdx, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset));
|
| + __ movzxbq(rcx, FieldOperand(rax, Map::kInObjectPropertiesOffset));
|
| + // Calculate unused properties past the end of the in-object properties.
|
| + __ subq(rdx, rcx);
|
| + // Done if no extra properties are to be allocated.
|
| + __ j(zero, &allocated);
|
| +
|
| + // Scale the number of elements by pointer size and add the header for
|
| + // FixedArrays to the start of the next object calculation from above.
|
| + // rbx: JSObject
|
| + // rdi: start of next object (will be start of FixedArray)
|
| + // 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);
|
| +
|
| + // Initialize the FixedArray.
|
| + // rbx: JSObject
|
| + // rdi: FixedArray
|
| + // rdx: number of elements
|
| + // rax: start of next object
|
| + __ Move(rcx, Factory::fixed_array_map());
|
| + __ movq(Operand(rdi, JSObject::kMapOffset), rcx); // setup the map
|
| + __ movl(Operand(rdi, FixedArray::kLengthOffset), rdx); // and length
|
| +
|
| + // Initialize the fields to undefined.
|
| + // rbx: JSObject
|
| + // rdi: FixedArray
|
| + // rax: start of next object
|
| + // rdx: number of elements
|
| + { Label loop, entry;
|
| + __ Move(rdx, Factory::undefined_value());
|
| + __ lea(rcx, Operand(rdi, FixedArray::kHeaderSize));
|
| + __ jmp(&entry);
|
| + __ bind(&loop);
|
| + __ movq(Operand(rcx, 0), rdx);
|
| + __ addq(rcx, Immediate(kPointerSize));
|
| + __ bind(&entry);
|
| + __ cmpq(rcx, rax);
|
| + __ j(below, &loop);
|
| + }
|
| +
|
| + // Store the initialized FixedArray into the properties field of
|
| + // the JSObject
|
| + // rbx: JSObject
|
| + // rdi: FixedArray
|
| + __ or_(rdi, Immediate(kHeapObjectTag)); // add the heap tag
|
| + __ movq(FieldOperand(rbx, JSObject::kPropertiesOffset), rdi);
|
| +
|
| +
|
| + // Continue with JSObject being successfully allocated
|
| + // rbx: JSObject
|
| + __ jmp(&allocated);
|
| +
|
| + // 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.
|
| + // 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);
|
| + }
|
| +
|
| // Allocate the new receiver object using the runtime call.
|
| // rdi: function (constructor)
|
| __ bind(&rt_call);
|
| - // Must restore edi (constructor) before calling runtime.
|
| + // Must restore rdi (constructor) before calling runtime.
|
| __ movq(rdi, Operand(rsp, 0));
|
| __ push(rdi);
|
| __ CallRuntime(Runtime::kNewObject, 1);
|
|
|