| 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.
|
| 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,124 @@
|
| }
|
|
|
|
|
| +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, 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 +1756,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 +1783,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) {
|
|
|