Change ARM exit frame layout and alingment handling
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 25 Jan 2011 07:49:39 +0000 (07:49 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 25 Jan 2011 07:49:39 +0000 (07:49 +0000)
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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6448 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/code-stubs-arm.cc
src/arm/frames-arm.cc
src/arm/frames-arm.h
src/arm/macro-assembler-arm.cc
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/x64/code-stubs-x64.cc

index a44600727579043f89852f211f7d61ef3838c3e2..273a3104f8a558b6746993a1f8c42fe6283c22a2 100644 (file)
@@ -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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
                               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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ 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.
@@ -2601,35 +2599,20 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   }
 #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);
-  masm->Jump(r5);
 
-  // Restore sp back to before aligning the stack.
-  if (alignment_before_call > 0) {
-    __ add(sp, sp, Operand(alignment_before_call));
-  }
+  // 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);
 
   if (always_allocate) {
     // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
@@ -2717,8 +2700,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
                &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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
                &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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
                &throw_termination_exception,
                &throw_out_of_memory_exception,
                true,
-               true,
-               kPointerSize);
+               true);
 
   __ bind(&throw_out_of_memory_exception);
   GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
index d2726cfcfe7ffc3f488331e59aa19ae6e6de4428..a805d280cad070f444d99b7aac1a5e4f2948681c 100644 (file)
@@ -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:
 #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);
 }
 
 
index f1be27f4bf4d1e5417a7700332c6ce6c3c665321..4aa8d6aa9ac1340237b7317a0d94c837c7c947cb 100644 (file)
@@ -107,21 +107,17 @@ class EntryFrameConstants : public AllStatic {
 
 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 @@ class StandardFrameConstants : public AllStatic {
   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;
 };
 
 
index a78de986e7cd63269b020aeff3c47e7f0de241dc..7431f3b0cdb3b6ed15eddc8edcf00b6ceb81d4da 100644 (file)
@@ -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::LeaveFrame(StackFrame::Type type) {
 
 
 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 @@ void MacroAssembler::EnterExitFrame(bool save_doubles) {
 
   // 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);
+      vstr(reg, fp, offset - ((i + 1) * kDoubleSize));
     }
-    // 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.
+    // 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 @@ int MacroAssembler::ActivationFrameAlignment() {
 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 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
   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);
 }
 
 
index bc7516a3fe3e6a18e54f68b5dacd81be250567d8..0ca5b4dae0ed0b7456fbd8b9cb95dc69a276dbd2 100644 (file)
@@ -600,8 +600,7 @@ class CEntryStub : public CodeStub {
                     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);
index 2c83662efd3853cafeac85d23da62fd5cf8d441e..5b745978d1e6dcba708a8c7e8e0938ab8485c0a2 100644 (file)
@@ -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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
                               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)
index 10c942a5b3a6d6f2f555048d9a27212daad40a90..929008fb48ac566400da6ea77c4b4ffa3d0fa894 100644 (file)
@@ -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 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
     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 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
   // 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)));
index a261b9d086d24219ef62ec92a4522a4ecd3ef8bd..1fe9fabc008b9b87a6aa2e0ca85976c99d36b34a 100644 (file)
@@ -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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
                               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).