From e73bfe98a4a3a1b18fda1aadd80f17e0362afb97 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Fri, 7 Aug 2009 12:52:32 +0000 Subject: [PATCH] Implement inline constructors for X64. Fix ia32 inline constructors a little. Fix a bug of a non-constant length between a call and its fixup. Review URL: http://codereview.chromium.org/164144 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2652 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ia32/builtins-ia32.cc | 14 ++--- src/x64/builtins-x64.cc | 153 +++++++++++++++++++++++++++++++++++++++++++++- src/x64/codegen-x64.cc | 13 +++- 3 files changed, 168 insertions(+), 12 deletions(-) diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 3cafd90..a70a9d2 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -140,7 +140,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { ExternalReference new_space_allocation_limit = ExternalReference::new_space_allocation_limit_address(); __ cmp(edi, Operand::StaticVariable(new_space_allocation_limit)); - __ j(greater_equal, &rt_call); + __ j(above_equal, &rt_call); // Allocated the JSObject, now initialize the fields. // eax: initial map // ebx: JSObject @@ -175,8 +175,8 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ or_(Operand(ebx), Immediate(kHeapObjectTag)); __ mov(Operand::StaticVariable(new_space_allocation_top), edi); - // Check if a properties array should be setup and allocate one if needed. - // Otherwise initialize the properties to the empty_fixed_array as well. + // Check if a non-empty properties array is needed. + // Allocate and initialize a FixedArray if it is. // eax: initial map // ebx: JSObject // edi: start of next object @@ -184,21 +184,19 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset)); // Calculate unused properties past the end of the in-object properties. __ sub(edx, Operand(ecx)); - __ test(edx, Operand(edx)); // 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. - // eax: initial map // ebx: JSObject // edi: start of next object (will be start of FixedArray) // edx: number of elements in properties array ASSERT(Heap::MaxObjectSizeInPagedSpace() > (FixedArray::kHeaderSize + 255*kPointerSize)); - __ lea(ecx, Operand(edi, edx, times_4, FixedArray::kHeaderSize)); + __ lea(ecx, Operand(edi, edx, times_pointer_size, FixedArray::kHeaderSize)); __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); - __ j(greater_equal, &undo_allocation); + __ j(above_equal, &undo_allocation); __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); // Initialize the FixedArray. @@ -223,7 +221,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ add(Operand(eax), Immediate(kPointerSize)); __ bind(&entry); __ cmp(eax, Operand(ecx)); - __ j(less, &loop); + __ j(below, &loop); } // Store the initialized FixedArray into the properties field of diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index 08f8338..087aaff 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -503,13 +503,160 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // 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; - - // TODO(x64): Implement inlined allocation. + if (FLAG_inline_new) { + Label undo_allocation; + // TODO(X64): Enable debugger support, using debug_step_in_fp. + + // 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); diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index c60b435..87f1040 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -5605,9 +5605,20 @@ void Reference::GetValue(TypeofState typeof_state) { Comment cmnt(masm, "[ Inlined named property load"); Result receiver = cgen_->frame()->Pop(); receiver.ToRegister(); - Result value = cgen_->allocator()->Allocate(); ASSERT(value.is_valid()); + // Cannot use r12 for receiver, because that changes + // the distance between a call and a fixup location, + // due to a special encoding of r12 as r/m in a ModR/M byte. + if (receiver.reg().is(r12)) { + // Swap receiver and value. + __ movq(value.reg(), receiver.reg()); + Result temp = receiver; + receiver = value; + value = temp; + cgen_->frame()->Spill(value.reg()); // r12 may have been shared. + } + DeferredReferenceGetNamedValue* deferred = new DeferredReferenceGetNamedValue(value.reg(), receiver.reg(), -- 2.7.4