Revision: 4425
Author: [email protected]
Date: Thu Apr 15 02:34:47 2010
Log: Ensure stack alignment in ARM port
In the CEntryStub keep track of the actual skew from the correct alignment
to ensure proper alignment before calling the runtime. Add checks to test
the expected skew when running on hardware.
Use the PrepareCallCFunction/CallCFunction in a few other places.
Add check to the ARM simulator for correct alignment.
Add option --sim-stack-alignment to set the stack alignment in the
simulator. Currntly only values 4 and 8 makes sense. 8 is the default to
make snapshots generated with the simulator work on hardware requiring 8
byte stack alignment.
Review URL: http://codereview.chromium.org/1530043
http://code.google.com/p/v8/source/detail?r=4425
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/codegen.h
/branches/bleeding_edge/src/flag-definitions.h
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/x64/codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Apr 15 01:45:27 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Apr 15 02:34:47 2010
@@ -5655,8 +5655,10 @@
} else {
// Call a native function to do a comparison between two non-NaNs.
// Call C routine that may not cause GC or other trouble.
- __ mov(r5, Operand(ExternalReference::compare_doubles()));
- __ Jump(r5); // Tail call.
+ __ push(lr);
+ __ PrepareCallCFunction(4, r5); // Two doubles count as 4 arguments.
+ __ CallCFunction(ExternalReference::compare_doubles(), 4);
+ __ pop(pc); // Return.
}
}
@@ -7083,7 +7085,8 @@
Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
bool do_gc,
- bool always_allocate) {
+ bool always_allocate,
+ int frame_alignment_skew) {
// r0: result parameter for PerformGC, if any
// r4: number of arguments including receiver (C callee-saved)
// r5: pointer to builtin function (C callee-saved)
@@ -7091,8 +7094,8 @@
if (do_gc) {
// Passing r0.
- ExternalReference gc_reference =
ExternalReference::perform_gc_function();
- __ Call(gc_reference.address(), RelocInfo::RUNTIME_ENTRY);
+ __ PrepareCallCFunction(1, r1);
+ __ CallCFunction(ExternalReference::perform_gc_function(), 1);
}
ExternalReference scope_depth =
@@ -7108,6 +7111,37 @@
// r0 = argc, r1 = argv
__ mov(r0, Operand(r4));
__ mov(r1, Operand(r6));
+
+ 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.
+ __ stop("Unexpected alignment");
+ __ bind(&alignment_as_expected);
+ }
+ }
+#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));
+ 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,
@@ -7116,9 +7150,14 @@
// 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->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));
+ }
if (always_allocate) {
// It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
@@ -7206,7 +7245,8 @@
&throw_termination_exception,
&throw_out_of_memory_exception,
false,
- false);
+ false,
+ -kPointerSize);
// Do space-specific GC and retry runtime call.
GenerateCore(masm,
@@ -7214,7 +7254,8 @@
&throw_termination_exception,
&throw_out_of_memory_exception,
true,
- false);
+ false,
+ 0);
// Do full GC and retry runtime call one final time.
Failure* failure = Failure::InternalError();
@@ -7224,7 +7265,8 @@
&throw_termination_exception,
&throw_out_of_memory_exception,
true,
- true);
+ true,
+ kPointerSize);
__ bind(&throw_out_of_memory_exception);
GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Apr 14
13:16:19 2010
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Apr 15
02:34:47 2010
@@ -355,10 +355,19 @@
// ip = sp + kPointerSize * #args;
add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
- // Align the stack at this point. After this point we have 5 pushes,
- // so in fact we have to unalign here! See also the assert on the
- // alignment in AlignStack.
- AlignStack(1);
+ // 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());
@@ -389,27 +398,20 @@
}
-void MacroAssembler::AlignStack(int offset) {
+int MacroAssembler::ActivationFrameAlignment() {
#if defined(V8_HOST_ARCH_ARM)
// Running on the real platform. Use the alignment as mandated by the
local
// environment.
// Note: This will break if we ever start generating snapshots on one ARM
// platform for another ARM platform with a different alignment.
- int activation_frame_alignment = OS::ActivationFrameAlignment();
+ return OS::ActivationFrameAlignment();
#else // defined(V8_HOST_ARCH_ARM)
// If we are using the simulator then we should always align to the
expected
// alignment. As the simulator is used to generate snapshots we do not
know
- // if the target platform will need alignment, so we will always align at
- // this point here.
- int activation_frame_alignment = 2 * kPointerSize;
+ // if the target platform will need alignment, so this is controlled
from a
+ // flag.
+ return FLAG_sim_stack_alignment;
#endif // defined(V8_HOST_ARCH_ARM)
- if (activation_frame_alignment != kPointerSize) {
- // This code needs to be made more general if this assert doesn't hold.
- ASSERT(activation_frame_alignment == 2 * kPointerSize);
- mov(r7, Operand(Smi::FromInt(0)));
- tst(sp, Operand(activation_frame_alignment - offset));
- push(r7, eq); // Conditional push instruction.
- }
}
@@ -1572,16 +1574,16 @@
void MacroAssembler::PrepareCallCFunction(int num_arguments, Register
scratch) {
- int frameAlignment = OS::ActivationFrameAlignment();
+ int frame_alignment = ActivationFrameAlignment();
// Up to four simple arguments are passed in registers r0..r3.
int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments -
4;
- if (frameAlignment > kPointerSize) {
+ if (frame_alignment > kPointerSize) {
// Make stack end at alignment and make room for num_arguments - 4
words
// and the original value of sp.
mov(scratch, sp);
sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
- ASSERT(IsPowerOf2(frameAlignment));
- and_(sp, sp, Operand(-frameAlignment));
+ ASSERT(IsPowerOf2(frame_alignment));
+ and_(sp, sp, Operand(-frame_alignment));
str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
@@ -1597,6 +1599,26 @@
void MacroAssembler::CallCFunction(Register function, int num_arguments) {
+ // Make sure that the stack is aligned before calling a C function unless
+ // running in the simulator. The simulator has its own alignment check
which
+ // provides more information.
+#if defined(V8_HOST_ARCH_ARM)
+ if (FLAG_debug_code) {
+ int frame_alignment = OS::ActivationFrameAlignment();
+ int frame_alignment_mask = frame_alignment - 1;
+ if (frame_alignment > kPointerSize) {
+ ASSERT(IsPowerOf2(frame_alignment));
+ Label alignment_as_expected;
+ tst(sp, Operand(frame_alignment_mask));
+ b(eq, &alignment_as_expected);
+ // Don't use Check here, as it will call Runtime_Abort possibly
+ // re-entering here.
+ stop("Unexpected alignment");
+ bind(&alignment_as_expected);
+ }
+ }
+#endif
+
// Just call directly. The function called cannot cause a GC, or
// allow preemption, so the return address in the link register
// stays correct.
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Apr 9
04:25:52 2010
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Thu Apr 15
02:34:47 2010
@@ -116,8 +116,8 @@
// Leave the current exit frame. Expects the return value in r0.
void LeaveExitFrame(ExitFrame::Mode mode);
- // Align the stack by optionally pushing a Smi zero.
- void AlignStack(int offset);
+ // Get the actual activation frame alignment for target environment.
+ static int ActivationFrameAlignment();
void LoadContext(Register dst, int context_chain_length);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Apr 12 06:15:39
2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Apr 15 02:34:47
2010
@@ -1249,6 +1249,11 @@
int swi = instr->SwiField();
switch (swi) {
case call_rt_redirected: {
+ // Check if stack is aligned. Error if not aligned is reported below
to
+ // include information on the function called.
+ bool stack_aligned =
+ (get_register(sp)
+ & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Redirection* redirection = Redirection::FromSwiInstruction(instr);
int32_t arg0 = get_register(r0);
int32_t arg1 = get_register(r1);
@@ -1262,12 +1267,17 @@
reinterpret_cast<intptr_t>(redirection->external_function());
SimulatorRuntimeFPCall target =
reinterpret_cast<SimulatorRuntimeFPCall>(external);
- if (::v8::internal::FLAG_trace_sim) {
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
double x, y;
GetFpArgs(&x, &y);
- PrintF("Call to host function at %p with args %f, %f\n",
+ PrintF("Call to host function at %p with args %f, %f",
FUNCTION_ADDR(target), x, y);
- }
+ if (!stack_aligned) {
+ PrintF(" with unaligned stack %08x\n", get_register(sp));
+ }
+ PrintF("\n");
+ }
+ CHECK(stack_aligned);
double result = target(arg0, arg1, arg2, arg3);
SetFpResult(result);
} else {
@@ -1275,15 +1285,20 @@
reinterpret_cast<int32_t>(redirection->external_function());
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
- if (::v8::internal::FLAG_trace_sim) {
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF(
- "Call to host function at %p with
args %08x, %08x, %08x, %08x\n",
+ "Call to host function at %p with
args %08x, %08x, %08x, %08x",
FUNCTION_ADDR(target),
arg0,
arg1,
arg2,
arg3);
- }
+ if (!stack_aligned) {
+ PrintF(" with unaligned stack %08x\n", get_register(sp));
+ }
+ PrintF("\n");
+ }
+ CHECK(stack_aligned);
int64_t result = target(arg0, arg1, arg2, arg3);
int32_t lo_res = static_cast<int32_t>(result);
int32_t hi_res = static_cast<int32_t>(result >> 32);
=======================================
--- /branches/bleeding_edge/src/codegen.h Wed Apr 14 07:46:15 2010
+++ /branches/bleeding_edge/src/codegen.h Thu Apr 15 02:34:47 2010
@@ -425,7 +425,8 @@
Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
bool do_gc,
- bool always_allocate_scope);
+ bool always_allocate_scope,
+ int alignment_skew = 0);
void GenerateThrowTOS(MacroAssembler* masm);
void GenerateThrowUncatchable(MacroAssembler* masm,
UncatchableExceptionType type);
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h Mon Apr 12 00:23:43 2010
+++ /branches/bleeding_edge/src/flag-definitions.h Thu Apr 15 02:34:47 2010
@@ -231,8 +231,10 @@
DEFINE_bool(optimize_ast, true, "optimize the ast")
// simulator-arm.cc and simulator-mips.cc
-DEFINE_bool(trace_sim, false, "trace simulator execution")
+DEFINE_bool(trace_sim, false, "Trace simulator execution")
DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions")
+DEFINE_int(sim_stack_alignment, 8,
+ "Stack alingment in bytes in simulator (4 or 8, 8 is default)")
// top.cc
DEFINE_bool(trace_exception, false,
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Wed Apr 14 07:46:15
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Apr 15 02:34:47
2010
@@ -11729,7 +11729,8 @@
Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
bool do_gc,
- bool always_allocate_scope) {
+ bool always_allocate_scope,
+ int /* alignment_skew */) {
// 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/x64/codegen-x64.cc Wed Apr 14 07:46:15 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Thu Apr 15 02:34:47 2010
@@ -8234,7 +8234,8 @@
Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
bool do_gc,
- bool always_allocate_scope) {
+ bool always_allocate_scope,
+ int /* alignment_skew */) {
// 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
To unsubscribe, reply using "remove me" as the subject.