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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4425 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9b31f11df6
commit
09aa20da08
@ -5655,8 +5655,10 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
|
|||||||
} else {
|
} else {
|
||||||
// Call a native function to do a comparison between two non-NaNs.
|
// Call a native function to do a comparison between two non-NaNs.
|
||||||
// Call C routine that may not cause GC or other trouble.
|
// Call C routine that may not cause GC or other trouble.
|
||||||
__ mov(r5, Operand(ExternalReference::compare_doubles()));
|
__ push(lr);
|
||||||
__ Jump(r5); // Tail call.
|
__ PrepareCallCFunction(4, r5); // Two doubles count as 4 arguments.
|
||||||
|
__ CallCFunction(ExternalReference::compare_doubles(), 4);
|
||||||
|
__ pop(pc); // Return.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7083,7 +7085,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
Label* throw_termination_exception,
|
Label* throw_termination_exception,
|
||||||
Label* throw_out_of_memory_exception,
|
Label* throw_out_of_memory_exception,
|
||||||
bool do_gc,
|
bool do_gc,
|
||||||
bool always_allocate) {
|
bool always_allocate,
|
||||||
|
int frame_alignment_skew) {
|
||||||
// r0: result parameter for PerformGC, if any
|
// r0: result parameter for PerformGC, if any
|
||||||
// r4: number of arguments including receiver (C callee-saved)
|
// r4: number of arguments including receiver (C callee-saved)
|
||||||
// r5: pointer to builtin function (C callee-saved)
|
// r5: pointer to builtin function (C callee-saved)
|
||||||
@ -7091,8 +7094,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
|
|
||||||
if (do_gc) {
|
if (do_gc) {
|
||||||
// Passing r0.
|
// Passing r0.
|
||||||
ExternalReference gc_reference = ExternalReference::perform_gc_function();
|
__ PrepareCallCFunction(1, r1);
|
||||||
__ Call(gc_reference.address(), RelocInfo::RUNTIME_ENTRY);
|
__ CallCFunction(ExternalReference::perform_gc_function(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalReference scope_depth =
|
ExternalReference scope_depth =
|
||||||
@ -7109,6 +7112,37 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
__ mov(r0, Operand(r4));
|
__ mov(r0, Operand(r4));
|
||||||
__ mov(r1, Operand(r6));
|
__ 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
|
// 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,
|
// 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 push it on the stack to be able to find it again, but we never
|
||||||
@ -7116,10 +7150,15 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
// support moving the C entry code stub. This should be fixed, but currently
|
// 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
|
// this is OK because the CEntryStub gets generated so early in the V8 boot
|
||||||
// sequence that it is not moving ever.
|
// 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->push(lr);
|
||||||
masm->Jump(r5);
|
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) {
|
if (always_allocate) {
|
||||||
// It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
|
// It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
|
||||||
// though (contain the result).
|
// though (contain the result).
|
||||||
@ -7206,7 +7245,8 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
|||||||
&throw_termination_exception,
|
&throw_termination_exception,
|
||||||
&throw_out_of_memory_exception,
|
&throw_out_of_memory_exception,
|
||||||
false,
|
false,
|
||||||
false);
|
false,
|
||||||
|
-kPointerSize);
|
||||||
|
|
||||||
// Do space-specific GC and retry runtime call.
|
// Do space-specific GC and retry runtime call.
|
||||||
GenerateCore(masm,
|
GenerateCore(masm,
|
||||||
@ -7214,7 +7254,8 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
|||||||
&throw_termination_exception,
|
&throw_termination_exception,
|
||||||
&throw_out_of_memory_exception,
|
&throw_out_of_memory_exception,
|
||||||
true,
|
true,
|
||||||
false);
|
false,
|
||||||
|
0);
|
||||||
|
|
||||||
// Do full GC and retry runtime call one final time.
|
// Do full GC and retry runtime call one final time.
|
||||||
Failure* failure = Failure::InternalError();
|
Failure* failure = Failure::InternalError();
|
||||||
@ -7224,7 +7265,8 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
|||||||
&throw_termination_exception,
|
&throw_termination_exception,
|
||||||
&throw_out_of_memory_exception,
|
&throw_out_of_memory_exception,
|
||||||
true,
|
true,
|
||||||
true);
|
true,
|
||||||
|
kPointerSize);
|
||||||
|
|
||||||
__ bind(&throw_out_of_memory_exception);
|
__ bind(&throw_out_of_memory_exception);
|
||||||
GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
|
GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
|
||||||
|
@ -355,10 +355,19 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
|
|||||||
// ip = sp + kPointerSize * #args;
|
// ip = sp + kPointerSize * #args;
|
||||||
add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||||
|
|
||||||
// Align the stack at this point. After this point we have 5 pushes,
|
// Prepare the stack to be aligned when calling into C. After this point there
|
||||||
// so in fact we have to unalign here! See also the assert on the
|
// are 5 pushes before the call into C, so the stack needs to be aligned after
|
||||||
// alignment in AlignStack.
|
// 5 pushes.
|
||||||
AlignStack(1);
|
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.
|
// Push in reverse order: caller_fp, sp_on_exit, and caller_pc.
|
||||||
stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
|
stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
|
||||||
@ -389,27 +398,20 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::AlignStack(int offset) {
|
int MacroAssembler::ActivationFrameAlignment() {
|
||||||
#if defined(V8_HOST_ARCH_ARM)
|
#if defined(V8_HOST_ARCH_ARM)
|
||||||
// Running on the real platform. Use the alignment as mandated by the local
|
// Running on the real platform. Use the alignment as mandated by the local
|
||||||
// environment.
|
// environment.
|
||||||
// Note: This will break if we ever start generating snapshots on one ARM
|
// Note: This will break if we ever start generating snapshots on one ARM
|
||||||
// platform for another ARM platform with a different alignment.
|
// platform for another ARM platform with a different alignment.
|
||||||
int activation_frame_alignment = OS::ActivationFrameAlignment();
|
return OS::ActivationFrameAlignment();
|
||||||
#else // defined(V8_HOST_ARCH_ARM)
|
#else // defined(V8_HOST_ARCH_ARM)
|
||||||
// If we are using the simulator then we should always align to the expected
|
// 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
|
// 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
|
// if the target platform will need alignment, so this is controlled from a
|
||||||
// this point here.
|
// flag.
|
||||||
int activation_frame_alignment = 2 * kPointerSize;
|
return FLAG_sim_stack_alignment;
|
||||||
#endif // defined(V8_HOST_ARCH_ARM)
|
#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::JumpIfInstanceTypeIsNotSequentialAscii(Register type,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
|
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.
|
// Up to four simple arguments are passed in registers r0..r3.
|
||||||
int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
|
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
|
// Make stack end at alignment and make room for num_arguments - 4 words
|
||||||
// and the original value of sp.
|
// and the original value of sp.
|
||||||
mov(scratch, sp);
|
mov(scratch, sp);
|
||||||
sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
|
sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
|
||||||
ASSERT(IsPowerOf2(frameAlignment));
|
ASSERT(IsPowerOf2(frame_alignment));
|
||||||
and_(sp, sp, Operand(-frameAlignment));
|
and_(sp, sp, Operand(-frame_alignment));
|
||||||
str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
|
str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
|
||||||
} else {
|
} else {
|
||||||
sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
|
sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
|
||||||
@ -1597,6 +1599,26 @@ void MacroAssembler::CallCFunction(ExternalReference function,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::CallCFunction(Register function, int num_arguments) {
|
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
|
// Just call directly. The function called cannot cause a GC, or
|
||||||
// allow preemption, so the return address in the link register
|
// allow preemption, so the return address in the link register
|
||||||
// stays correct.
|
// stays correct.
|
||||||
|
@ -116,8 +116,8 @@ class MacroAssembler: public Assembler {
|
|||||||
// Leave the current exit frame. Expects the return value in r0.
|
// Leave the current exit frame. Expects the return value in r0.
|
||||||
void LeaveExitFrame(ExitFrame::Mode mode);
|
void LeaveExitFrame(ExitFrame::Mode mode);
|
||||||
|
|
||||||
// Align the stack by optionally pushing a Smi zero.
|
// Get the actual activation frame alignment for target environment.
|
||||||
void AlignStack(int offset);
|
static int ActivationFrameAlignment();
|
||||||
|
|
||||||
void LoadContext(Register dst, int context_chain_length);
|
void LoadContext(Register dst, int context_chain_length);
|
||||||
|
|
||||||
|
@ -1249,6 +1249,11 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
|
|||||||
int swi = instr->SwiField();
|
int swi = instr->SwiField();
|
||||||
switch (swi) {
|
switch (swi) {
|
||||||
case call_rt_redirected: {
|
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);
|
Redirection* redirection = Redirection::FromSwiInstruction(instr);
|
||||||
int32_t arg0 = get_register(r0);
|
int32_t arg0 = get_register(r0);
|
||||||
int32_t arg1 = get_register(r1);
|
int32_t arg1 = get_register(r1);
|
||||||
@ -1262,12 +1267,17 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
|
|||||||
reinterpret_cast<intptr_t>(redirection->external_function());
|
reinterpret_cast<intptr_t>(redirection->external_function());
|
||||||
SimulatorRuntimeFPCall target =
|
SimulatorRuntimeFPCall target =
|
||||||
reinterpret_cast<SimulatorRuntimeFPCall>(external);
|
reinterpret_cast<SimulatorRuntimeFPCall>(external);
|
||||||
if (::v8::internal::FLAG_trace_sim) {
|
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
||||||
double x, y;
|
double x, y;
|
||||||
GetFpArgs(&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);
|
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);
|
double result = target(arg0, arg1, arg2, arg3);
|
||||||
SetFpResult(result);
|
SetFpResult(result);
|
||||||
} else {
|
} else {
|
||||||
@ -1275,15 +1285,20 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
|
|||||||
reinterpret_cast<int32_t>(redirection->external_function());
|
reinterpret_cast<int32_t>(redirection->external_function());
|
||||||
SimulatorRuntimeCall target =
|
SimulatorRuntimeCall target =
|
||||||
reinterpret_cast<SimulatorRuntimeCall>(external);
|
reinterpret_cast<SimulatorRuntimeCall>(external);
|
||||||
if (::v8::internal::FLAG_trace_sim) {
|
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
||||||
PrintF(
|
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),
|
FUNCTION_ADDR(target),
|
||||||
arg0,
|
arg0,
|
||||||
arg1,
|
arg1,
|
||||||
arg2,
|
arg2,
|
||||||
arg3);
|
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);
|
int64_t result = target(arg0, arg1, arg2, arg3);
|
||||||
int32_t lo_res = static_cast<int32_t>(result);
|
int32_t lo_res = static_cast<int32_t>(result);
|
||||||
int32_t hi_res = static_cast<int32_t>(result >> 32);
|
int32_t hi_res = static_cast<int32_t>(result >> 32);
|
||||||
|
@ -425,7 +425,8 @@ class CEntryStub : public CodeStub {
|
|||||||
Label* throw_termination_exception,
|
Label* throw_termination_exception,
|
||||||
Label* throw_out_of_memory_exception,
|
Label* throw_out_of_memory_exception,
|
||||||
bool do_gc,
|
bool do_gc,
|
||||||
bool always_allocate_scope);
|
bool always_allocate_scope,
|
||||||
|
int alignment_skew = 0);
|
||||||
void GenerateThrowTOS(MacroAssembler* masm);
|
void GenerateThrowTOS(MacroAssembler* masm);
|
||||||
void GenerateThrowUncatchable(MacroAssembler* masm,
|
void GenerateThrowUncatchable(MacroAssembler* masm,
|
||||||
UncatchableExceptionType type);
|
UncatchableExceptionType type);
|
||||||
|
@ -231,8 +231,10 @@ DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
|
|||||||
DEFINE_bool(optimize_ast, true, "optimize the ast")
|
DEFINE_bool(optimize_ast, true, "optimize the ast")
|
||||||
|
|
||||||
// simulator-arm.cc and simulator-mips.cc
|
// 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(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
|
// top.cc
|
||||||
DEFINE_bool(trace_exception, false,
|
DEFINE_bool(trace_exception, false,
|
||||||
|
@ -11729,7 +11729,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
Label* throw_termination_exception,
|
Label* throw_termination_exception,
|
||||||
Label* throw_out_of_memory_exception,
|
Label* throw_out_of_memory_exception,
|
||||||
bool do_gc,
|
bool do_gc,
|
||||||
bool always_allocate_scope) {
|
bool always_allocate_scope,
|
||||||
|
int /* alignment_skew */) {
|
||||||
// eax: result parameter for PerformGC, if any
|
// eax: result parameter for PerformGC, if any
|
||||||
// ebx: pointer to C function (C callee-saved)
|
// ebx: pointer to C function (C callee-saved)
|
||||||
// ebp: frame pointer (restored after C call)
|
// ebp: frame pointer (restored after C call)
|
||||||
|
@ -8234,7 +8234,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
Label* throw_termination_exception,
|
Label* throw_termination_exception,
|
||||||
Label* throw_out_of_memory_exception,
|
Label* throw_out_of_memory_exception,
|
||||||
bool do_gc,
|
bool do_gc,
|
||||||
bool always_allocate_scope) {
|
bool always_allocate_scope,
|
||||||
|
int /* alignment_skew */) {
|
||||||
// rax: result parameter for PerformGC, if any.
|
// rax: result parameter for PerformGC, if any.
|
||||||
// rbx: pointer to C function (C callee-saved).
|
// rbx: pointer to C function (C callee-saved).
|
||||||
// rbp: frame pointer (restored after C call).
|
// rbp: frame pointer (restored after C call).
|
||||||
|
Loading…
Reference in New Issue
Block a user