Index: src/arm/macro-assembler-arm.cc |
=================================================================== |
--- src/arm/macro-assembler-arm.cc (revision 6213) |
+++ src/arm/macro-assembler-arm.cc (working copy) |
@@ -542,30 +542,23 @@ |
} |
-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. |
+void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { |
+ // Prepare the stack to be aligned when calling into C. |
+ int pending_pushes = stack_space + 4; // 4 pushes in this function. |
antonm
2011/01/21 17:56:36
May you explain: it looks like only pending_pushes
Zaheer
2011/01/24 09:43:31
sorry i miss your comment.
antonm
2011/01/26 11:36:37
I am sorry, I meant it's somewhat strange to see p
Zaheer
2011/02/02 10:05:58
not required with the rebase.
|
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. |
+ tst(sp, Operand(frame_alignment_mask)); |
+ // If stack is unaligned, align it if requesting even slots otherwise |
+ // unalign it if requesting odd slots. |
+ if (pending_pushes % 2 == 0) { |
+ push(r7, ne); |
+ } else { |
+ push(r7, eq); |
+ } |
} |
// Push in reverse order: caller_fp, sp_on_exit, and caller_pc. |
@@ -581,10 +574,6 @@ |
mov(ip, Operand(ExternalReference(Top::k_context_address))); |
str(cp, MemOperand(ip)); |
- // Setup argc and the builtin function in callee-saved registers. |
- mov(r4, Operand(r0)); |
- mov(r5, Operand(r1)); |
- |
// Optionally save all double registers. |
if (save_doubles) { |
// TODO(regis): Use vstrm instruction. |
@@ -1397,6 +1386,121 @@ |
} |
+MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub, Condition cond) { |
+ ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs |
+ Object* result; |
+ { MaybeObject* maybe_result = stub->TryGetCode(); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); |
+ return result; |
+} |
+ |
+void MacroAssembler::PrepareCallApiFunction(int arg_stack_space, |
+ int unwind_space) { |
+ add(ip, sp, Operand(unwind_space * kPointerSize)); |
+ EnterExitFrame(false, arg_stack_space + 1); |
+ |
+ // Create space for the arguments below the exit frame. |
+ // +- exit frame -+- arguments -+- stack grows here -+ |
+ // 1 for the return address |
+ sub(sp, sp, Operand((arg_stack_space + 1) * kPointerSize)); |
+} |
+ |
+static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { |
+ int64_t offset = (ref0.address() - ref1.address()); |
+ // Check that fits into int. |
+ ASSERT(static_cast<int>(offset) == offset); |
+ return static_cast<int>(offset); |
+} |
+ |
+MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( |
+ ApiFunction* function) { |
+ ExternalReference next_address = |
+ ExternalReference::handle_scope_next_address(); |
+ const int kNextOffset = 0; |
+ const int kLimitOffset = AddressOffset( |
+ ExternalReference::handle_scope_limit_address(), |
+ next_address); |
+ const int kLevelOffset = AddressOffset( |
+ ExternalReference::handle_scope_level_address(), |
+ next_address); |
+ |
+ // Allocate HandleScope in callee-save registers. |
+ mov(r7, Operand(next_address)); |
+ ldr(r4, MemOperand(r7, kNextOffset)); |
+ ldr(r5, MemOperand(r7, kLimitOffset)); |
+ ldr(r6, MemOperand(r7, kLevelOffset)); |
+ add(r6, r6, Operand(1)); |
+ str(r6, MemOperand(r7, kLevelOffset)); |
+ |
+ // Native call returns to the DirectCEntry stub which redirects to the |
+ // return address pushed on stack (could have moved after GC). |
+ DirectCEntryStub stub; |
+ mov(lr, Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), |
+ RelocInfo::CODE_TARGET)); |
+ |
+ // Push return address (accessible to GC through exit frame pc). |
+ ExternalReference ref = |
+ ExternalReference(function, false, ExternalReference::DIRECT_CALL); |
+ mov(r2, Operand(reinterpret_cast<intptr_t>(ref.address()))); |
+ add(ip, pc, Operand(4)); |
+ str(ip, MemOperand(fp, ExitFrameConstants::kPCOffset)); |
+ Jump(r2); // Call the api function. |
+ |
+ Label promote_scheduled_exception; |
+ Label delete_allocated_handles; |
+ Label leave_exit_frame; |
+ |
+ // If result is non-zero, dereference to get the result value |
+ // otherwise set it to undefined. |
+ cmp(r0, Operand(0)); |
+ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
+ ldr(r0, MemOperand(r0), ne); |
+ |
+ // No more valid handles (the result handle was the last one). Restore |
+ // previous handle scope. |
+ str(r4, MemOperand(r7, kNextOffset)); |
+ if (FLAG_debug_code) { |
+ ldr(r1, MemOperand(r7, kLevelOffset)); |
+ cmp(r1, r6); |
+ Check(eq, "Unexpected level after return from api call"); |
+ } |
+ sub(r6, r6, Operand(1)); |
+ str(r6, MemOperand(r7, kLevelOffset)); |
+ ldr(ip, MemOperand(r7, kLimitOffset)); |
+ cmp(r5, ip); |
+ b(ne, &delete_allocated_handles); |
+ |
+ // Check if the function scheduled an exception. |
+ bind(&leave_exit_frame); |
+ LoadRoot(r4, Heap::kTheHoleValueRootIndex); |
+ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address))); |
+ ldr(r5, MemOperand(ip)); |
+ cmp(r4, r5); |
+ b(ne, &promote_scheduled_exception); |
+ LeaveExitFrame(false); |
+ |
+ bind(&promote_scheduled_exception); |
+ MaybeObject* result = TryTailCallExternalReference( |
+ ExternalReference(Runtime::kPromoteScheduledException), 0, 1); |
+ if (result->IsFailure()) { |
+ return result; |
+ } |
+ |
+ // HandleScope limit has changed. Delete allocated extensions. |
+ bind(&delete_allocated_handles); |
+ str(r5, MemOperand(r7, kLimitOffset)); |
+ mov(r4, r0); |
+ PrepareCallCFunction(0, r5); |
+ CallCFunction(ExternalReference::delete_handle_scope_extensions(), 0); |
+ mov(r0, r4); |
+ jmp(&leave_exit_frame); |
+ |
+ return result; |
+} |
+ |
+ |
void MacroAssembler::IllegalOperation(int num_arguments) { |
if (num_arguments > 0) { |
add(sp, sp, Operand(num_arguments * kPointerSize)); |
@@ -1649,6 +1753,15 @@ |
JumpToExternalReference(ext); |
} |
+MaybeObject* MacroAssembler::TryTailCallExternalReference( |
+ const ExternalReference& ext, int num_arguments, int result_size) { |
+ // TODO(1236192): Most runtime routines don't need the number of |
+ // arguments passed in because it is constant. At some point we |
+ // should remove this need and make the runtime routine entry code |
+ // smarter. |
+ mov(r0, Operand(num_arguments)); |
+ return TryJumpToExternalReference(ext); |
+} |
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, |
int num_arguments, |
@@ -1667,6 +1780,16 @@ |
Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
} |
+MaybeObject* MacroAssembler::TryJumpToExternalReference( |
+ const ExternalReference& builtin) { |
+#if defined(__thumb__) |
+ // Thumb mode builtin. |
+ ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); |
+#endif |
+ mov(r1, Operand(builtin)); |
+ CEntryStub stub(1); |
+ return TryTailCallStub(&stub); |
+} |
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
InvokeJSFlags flags) { |