Revision: 6448
Author: [email protected]
Date: Mon Jan 24 23:49:39 2011
Log: Change ARM exit frame layout and alingment handling

Change the ARM exit frame to have the same layout as the IA32 exit frame. This basically re-arranges the order of fp and sp and changes the sp location of the entry frame to hold the sp used by the gc and not the sp for popping the arguments. This removes the option of tearing down the frame and returning using one ldm instruction.

The main motivation for this is to avoid pushing an alignment word before generating the entry frame. The GC handling of optimized frames process the registers pushed as part of a safepoint and asumes that these are at the top of the frame, so if an alignment word is pushed this processing will be one off.

The alignment handling in the C entry stub have also been simplified. Now the value of lr is stored to a stack slot already reserved avoiding pushing it and keeping track of "frame skew".

This does result in more instructions in the exit frame on ARM, but we can look into improving this later.
Review URL: http://codereview.chromium.org/6247019
http://code.google.com/p/v8/source/detail?r=6448

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/frames-arm.cc
 /branches/bleeding_edge/src/arm/frames-arm.h
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Jan 21 03:28:35 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Jan 24 23:49:39 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -2557,8 +2557,7 @@
                               Label* throw_termination_exception,
                               Label* throw_out_of_memory_exception,
                               bool do_gc,
-                              bool always_allocate,
-                              int frame_alignment_skew) {
+                              bool always_allocate) {
   // r0: result parameter for PerformGC, if any
   // r4: number of arguments including receiver  (C callee-saved)
   // r5: pointer to builtin function  (C callee-saved)
@@ -2584,14 +2583,13 @@
   __ mov(r0, Operand(r4));
   __ mov(r1, Operand(r6));

+#if defined(V8_HOST_ARCH_ARM)
   int frame_alignment = MacroAssembler::ActivationFrameAlignment();
   int frame_alignment_mask = frame_alignment - 1;
-#if defined(V8_HOST_ARCH_ARM)
   if (FLAG_debug_code) {
     if (frame_alignment > kPointerSize) {
       Label alignment_as_expected;
       ASSERT(IsPowerOf2(frame_alignment));
-      __ sub(r2, sp, Operand(frame_alignment_skew));
       __ tst(r2, Operand(frame_alignment_mask));
       __ b(eq, &alignment_as_expected);
// Don't use Check here, as it will call Runtime_Abort re-entering here.
@@ -2600,36 +2598,21 @@
     }
   }
 #endif
-
- // Just before the call (jump) below lr is pushed, so the actual alignment is
-  // adding one to the current skew.
-  int alignment_before_call =
-      (frame_alignment_skew + kPointerSize) & frame_alignment_mask;
-  if (alignment_before_call > 0) {
-    // Push until the alignment before the call is met.
-    __ mov(r2, Operand(0, RelocInfo::NONE));
-    for (int i = alignment_before_call;
-        (i & frame_alignment_mask) != 0;
-        i += kPointerSize) {
-      __ push(r2);
-    }
-  }

   // TODO(1242173): To let the GC traverse the return address of the exit
   // frames, we need to know where the return address is. Right now,
-  // we push it on the stack to be able to find it again, but we never
+  // we store it on the stack to be able to find it again, but we never
   // restore from it in case of changes, which makes it impossible to
// support moving the C entry code stub. This should be fixed, but currently // this is OK because the CEntryStub gets generated so early in the V8 boot
   // sequence that it is not moving ever.
-  masm->add(lr, pc, Operand(4));  // Compute return address: (pc + 8) + 4
-  masm->push(lr);
+
+ // Compute the return address in lr to return to after the jump below. Pc is + // already at '+ 8' from the current instruction but return is after three
+  // instructions so add another 4 to pc to get the return address.
+  masm->add(lr, pc, Operand(4));
+  __ str(lr, MemOperand(sp, 0));
   masm->Jump(r5);
-
-  // Restore sp back to before aligning the stack.
-  if (alignment_before_call > 0) {
-    __ add(sp, sp, Operand(alignment_before_call));
-  }

   if (always_allocate) {
     // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
@@ -2717,8 +2700,7 @@
                &throw_termination_exception,
                &throw_out_of_memory_exception,
                false,
-               false,
-               -kPointerSize);
+               false);

   // Do space-specific GC and retry runtime call.
   GenerateCore(masm,
@@ -2726,8 +2708,7 @@
                &throw_termination_exception,
                &throw_out_of_memory_exception,
                true,
-               false,
-               0);
+               false);

   // Do full GC and retry runtime call one final time.
   Failure* failure = Failure::InternalError();
@@ -2737,8 +2718,7 @@
                &throw_termination_exception,
                &throw_out_of_memory_exception,
                true,
-               true,
-               kPointerSize);
+               true);

   __ bind(&throw_out_of_memory_exception);
   GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
=======================================
--- /branches/bleeding_edge/src/arm/frames-arm.cc       Tue Dec  7 03:31:57 2010
+++ /branches/bleeding_edge/src/arm/frames-arm.cc       Mon Jan 24 23:49:39 2011
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -30,20 +30,13 @@
 #if defined(V8_TARGET_ARCH_ARM)

 #include "frames-inl.h"
-#include "arm/assembler-arm-inl.h"
-

 namespace v8 {
 namespace internal {


 Address ExitFrame::ComputeStackPointer(Address fp) {
- Address marker = Memory::Address_at(fp + ExitFrameConstants::kMarkerOffset);
-  Address sp = fp + ExitFrameConstants::kSPOffset;
-  if (marker == NULL) {
-    sp -= DwVfpRegister::kNumRegisters * kDoubleSize + 2 * kPointerSize;
-  }
-  return sp;
+  return Memory::Address_at(fp + ExitFrameConstants::kSPOffset);
 }


=======================================
--- /branches/bleeding_edge/src/arm/frames-arm.h        Thu Jan 20 00:08:36 2011
+++ /branches/bleeding_edge/src/arm/frames-arm.h        Mon Jan 24 23:49:39 2011
@@ -107,21 +107,17 @@

 class ExitFrameConstants : public AllStatic {
  public:
-  static const int kCodeOffset = -1 * kPointerSize;
+  static const int kCodeOffset = -2 * kPointerSize;
   static const int kSPOffset = -1 * kPointerSize;

-  // TODO(regis): Use a patched sp value on the stack instead.
-  // A marker of 0 indicates that double registers are saved.
-  static const int kMarkerOffset = -2 * kPointerSize;
-
   // The caller fields are below the frame pointer on the stack.
-  static const int kCallerFPOffset = +0 * kPointerSize;
-  // The calling JS function is between FP and PC.
-  static const int kCallerPCOffset = +2 * kPointerSize;
+  static const int kCallerFPOffset = 0 * kPointerSize;
+  // The calling JS function is below FP.
+  static const int kCallerPCOffset = 1 * kPointerSize;

   // FP-relative displacement of the caller's SP.  It points just
   // below the saved PC.
-  static const int kCallerSPDisplacement = +3 * kPointerSize;
+  static const int kCallerSPDisplacement = 2 * kPointerSize;
 };


@@ -131,8 +127,8 @@
   static const int kMarkerOffset      = -2 * kPointerSize;
   static const int kContextOffset     = -1 * kPointerSize;
   static const int kCallerFPOffset    =  0 * kPointerSize;
-  static const int kCallerPCOffset    = +1 * kPointerSize;
-  static const int kCallerSPOffset    = +2 * kPointerSize;
+  static const int kCallerPCOffset    =  1 * kPointerSize;
+  static const int kCallerSPOffset    =  2 * kPointerSize;
 };


=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jan 20 06:20:54 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Jan 24 23:49:39 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -615,37 +615,24 @@


 void MacroAssembler::EnterExitFrame(bool save_doubles) {
-  // r0 is argc.
-  // Compute callee's stack pointer before making changes and save it as
-  // ip register so that it is restored as sp register on exit, thereby
-  // popping the args.
-
-  // ip = sp + kPointerSize * #args;
-  add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
-
-  // Compute the argv pointer and keep it in a callee-saved register.
-  sub(r6, ip, Operand(kPointerSize));
-
- // Prepare the stack to be aligned when calling into C. After this point there - // are 5 pushes before the call into C, so the stack needs to be aligned after
-  // 5 pushes.
-  int frame_alignment = ActivationFrameAlignment();
-  int frame_alignment_mask = frame_alignment - 1;
-  if (frame_alignment != kPointerSize) {
- // The following code needs to be more general if this assert does not hold.
-    ASSERT(frame_alignment == 2 * kPointerSize);
-    // With 5 pushes left the frame must be unaligned at this point.
-    mov(r7, Operand(Smi::FromInt(0)));
- tst(sp, Operand((frame_alignment - kPointerSize) & frame_alignment_mask));
-    push(r7, eq);  // Push if aligned to make it unaligned.
-  }
-
-  // Push in reverse order: caller_fp, sp_on_exit, and caller_pc.
-  stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
+  // Compute the argv pointer in a callee-saved register.
+  add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
+  sub(r6, r6, Operand(kPointerSize));
+
+  // Setup the frame structure on the stack.
+  ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
+  ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
+  ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
+  Push(lr, fp);
   mov(fp, Operand(sp));  // Setup new frame pointer.
-
+  // Reserve room for saved entry sp and code object.
+  sub(sp, sp, Operand(2 * kPointerSize));
+  if (FLAG_debug_code) {
+    mov(ip, Operand(0));
+    str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
+  }
   mov(ip, Operand(CodeObject()));
-  push(ip);  // Accessed from ExitFrame::code_slot.
+  str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));

   // Save the frame pointer and the context in top.
   mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
@@ -659,25 +646,30 @@

   // Optionally save all double registers.
   if (save_doubles) {
-    // TODO(regis): Use vstrm instruction.
- // The stack alignment code above made sp unaligned, so add space for one
-    // more double register and use aligned addresses.
-    ASSERT(kDoubleSize == frame_alignment);
-    // Mark the frame as containing doubles by pushing a non-valid return
-    // address, i.e. 0.
-    ASSERT(ExitFrameConstants::kMarkerOffset == -2 * kPointerSize);
-    mov(ip, Operand(0));  // Marker and alignment word.
-    push(ip);
-    int space = DwVfpRegister::kNumRegisters * kDoubleSize + kPointerSize;
-    sub(sp, sp, Operand(space));
+    sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize));
+    const int offset = -2 * kPointerSize;
     for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
       DwVfpRegister reg = DwVfpRegister::from_code(i);
-      vstr(reg, sp, i * kDoubleSize + kPointerSize);
-    }
-    // Note that d0 will be accessible at fp - 2*kPointerSize -
- // DwVfpRegister::kNumRegisters * kDoubleSize, since the code slot and the
-    // alignment word were pushed after the fp.
-  }
+      vstr(reg, fp, offset - ((i + 1) * kDoubleSize));
+    }
+    // Note that d0 will be accessible at
+ // fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize,
+    // since the sp slot and code slot were pushed after the fp.
+  }
+
+  // Reserve place for the return address and align the frame preparing for
+  // calling the runtime function.
+  const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
+  sub(sp, sp, Operand(kPointerSize));
+  if (frame_alignment > 0) {
+    ASSERT(IsPowerOf2(frame_alignment));
+    and_(sp, sp, Operand(-frame_alignment));
+  }
+
+  // Set the exit frame sp value to point just before the return address
+  // location.
+  add(ip, sp, Operand(kPointerSize));
+  str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
 }


@@ -715,12 +707,10 @@
 void MacroAssembler::LeaveExitFrame(bool save_doubles) {
   // Optionally restore all double registers.
   if (save_doubles) {
-    // TODO(regis): Use vldrm instruction.
     for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
       DwVfpRegister reg = DwVfpRegister::from_code(i);
-      // Register d15 is just below the marker.
-      const int offset = ExitFrameConstants::kMarkerOffset;
- vldr(reg, fp, (i - DwVfpRegister::kNumRegisters) * kDoubleSize + offset);
+      const int offset = -2 * kPointerSize;
+      vldr(reg, fp, offset - ((i + 1) * kDoubleSize));
     }
   }

@@ -736,9 +726,12 @@
   str(r3, MemOperand(ip));
 #endif

-  // Pop the arguments, restore registers, and return.
-  mov(sp, Operand(fp));  // respect ABI stack constraint
-  ldm(ia, sp, fp.bit() | sp.bit() | pc.bit());
+  // Tear down the exit frame, pop the arguments, and return. Callee-saved
+  // register r4 still holds argc.
+  mov(sp, Operand(fp));
+  ldm(ia_w, sp, fp.bit() | lr.bit());
+  add(sp, sp, Operand(r4, LSL, kPointerSizeLog2));
+  mov(pc, lr);
 }


=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Fri Jan 21 03:28:35 2011
+++ /branches/bleeding_edge/src/code-stubs.h    Mon Jan 24 23:49:39 2011
@@ -600,8 +600,7 @@
                     Label* throw_termination_exception,
                     Label* throw_out_of_memory_exception,
                     bool do_gc,
-                    bool always_allocate_scope,
-                    int alignment_skew = 0);
+                    bool always_allocate_scope);
   void GenerateThrowTOS(MacroAssembler* masm);
   void GenerateThrowUncatchable(MacroAssembler* masm,
                                 UncatchableExceptionType type);
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Jan 21 03:28:35 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Jan 24 23:49:39 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -4660,8 +4660,7 @@
                               Label* throw_termination_exception,
                               Label* throw_out_of_memory_exception,
                               bool do_gc,
-                              bool always_allocate_scope,
-                              int /* alignment_skew */) {
+                              bool always_allocate_scope) {
   // eax: result parameter for PerformGC, if any
   // ebx: pointer to C function  (C callee-saved)
   // ebp: frame pointer  (restored after C call)
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Jan 14 02:57:49 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Mon Jan 24 23:49:39 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -339,7 +339,7 @@
     CpuFeatures::Scope scope(SSE2);
int space = XMMRegister::kNumRegisters * kDoubleSize + argc * kPointerSize;
     sub(Operand(esp), Immediate(space));
-    int offset = -2 * kPointerSize;
+    const int offset = -2 * kPointerSize;
     for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
       XMMRegister reg = XMMRegister::from_code(i);
       movdbl(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg);
@@ -382,7 +382,7 @@
   // Optionally restore all XMM registers.
   if (save_doubles) {
     CpuFeatures::Scope scope(SSE2);
-    int offset = -2 * kPointerSize;
+    const int offset = -2 * kPointerSize;
     for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
       XMMRegister reg = XMMRegister::from_code(i);
       movdbl(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Jan 21 03:28:35 2011 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Jan 24 23:49:39 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -2773,8 +2773,7 @@
                               Label* throw_termination_exception,
                               Label* throw_out_of_memory_exception,
                               bool do_gc,
-                              bool always_allocate_scope,
-                              int /* alignment_skew */) {
+                              bool always_allocate_scope) {
   // rax: result parameter for PerformGC, if any.
   // rbx: pointer to C function  (C callee-saved).
   // rbp: frame pointer  (restored after C call).

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to