Implement inline constructors for X64. Fix ia32 inline constructors a little. Fix...
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 7 Aug 2009 12:52:32 +0000 (12:52 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 7 Aug 2009 12:52:32 +0000 (12:52 +0000)
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
src/x64/builtins-x64.cc
src/x64/codegen-x64.cc

index 3cafd90..a70a9d2 100644 (file)
@@ -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
index 08f8338..087aaff 100644 (file)
@@ -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);
index c60b435..87f1040 100644 (file)
@@ -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(),