From 68a0a108c483ff0c48df34d3b633636f88f437b3 Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Fri, 9 Apr 2010 11:25:52 +0000 Subject: [PATCH] Call to C function support in macro assembler Implement macro assembler operations PrepareCallCFunction and CallCFunction like on both Intel platforms. Used these for direct calls to C functions. Review URL: http://codereview.chromium.org/1549031 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4374 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.cc | 30 +++++++--------- src/arm/macro-assembler-arm.cc | 39 +++++++++++++++++++++ src/arm/macro-assembler-arm.h | 18 ++++++++++ src/arm/regexp-macro-assembler-arm.cc | 49 ++++----------------------- src/arm/regexp-macro-assembler-arm.h | 16 --------- 5 files changed, 77 insertions(+), 75 deletions(-) diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 7768532763..9fe1c2ca2a 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -3956,8 +3956,9 @@ void CodeGenerator::GenerateRandomHeapNumber( __ CallRuntime(Runtime::kNumberUnaryMinus, 1); __ bind(&heapnumber_allocated); - __ Call(ExternalReference::fill_heap_number_with_random_function().address(), - RelocInfo::RUNTIME_ENTRY); + __ PrepareCallCFunction(1, r1); + __ CallCFunction( + ExternalReference::fill_heap_number_with_random_function(), 1); frame_->EmitPush(r0); } @@ -5958,28 +5959,23 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(MacroAssembler* masm, // r5: Address of heap number for result. __ push(lr); // For later. - __ push(r5); // Address of heap number that is answer. - __ AlignStack(0); - // Call C routine that may not cause GC or other trouble. - __ mov(r5, Operand(ExternalReference::double_fp_operation(op_))); - __ Call(r5); - __ pop(r4); // Address of heap number. - __ cmp(r4, Operand(Smi::FromInt(0))); - __ pop(r4, eq); // Conditional pop instruction - // to get rid of alignment push. + __ PrepareCallCFunction(4, r4); // Two doubles count as 4 arguments. + // Call C routine that may not cause GC or other trouble. r5 is callee + // save. + __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); // Store answer in the overwritable heap number. #if !defined(USE_ARM_EABI) // Double returned in fp coprocessor register 0 and 1, encoded as register // cr8. Offsets must be divisible by 4 for coprocessor so we need to - // substract the tag from r4. - __ sub(r5, r4, Operand(kHeapObjectTag)); - __ stc(p1, cr8, MemOperand(r5, HeapNumber::kValueOffset)); + // substract the tag from r5. + __ sub(r4, r5, Operand(kHeapObjectTag)); + __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset)); #else // Double returned in registers 0 and 1. - __ str(r0, FieldMemOperand(r4, HeapNumber::kValueOffset)); - __ str(r1, FieldMemOperand(r4, HeapNumber::kValueOffset + 4)); + __ str(r0, FieldMemOperand(r5, HeapNumber::kValueOffset)); + __ str(r1, FieldMemOperand(r5, HeapNumber::kValueOffset + 4)); #endif - __ mov(r0, Operand(r4)); + __ mov(r0, Operand(r5)); // And we are done. __ pop(pc); } diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 80687a3fed..1131760db3 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1557,6 +1557,45 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type, } +void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { + int frameAlignment = OS::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) { + // 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)); + str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); + } else { + sub(sp, sp, Operand(stack_passed_arguments * kPointerSize)); + } +} + + +void MacroAssembler::CallCFunction(ExternalReference function, + int num_arguments) { + mov(ip, Operand(function)); + CallCFunction(ip, num_arguments); +} + + +void MacroAssembler::CallCFunction(Register function, int num_arguments) { + // Just call directly. The function called cannot cause a GC, or + // allow preemption, so the return address in the link register + // stays correct. + Call(function); + int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4; + if (OS::ActivationFrameAlignment() > kPointerSize) { + ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); + } else { + add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); + } +} + + #ifdef ENABLE_DEBUGGER_SUPPORT CodePatcher::CodePatcher(byte* address, int instructions) : address_(address), diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 5ff401eb4d..fa3a7ee65f 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -373,6 +373,24 @@ class MacroAssembler: public Assembler { int num_arguments, int result_size); + // Before calling a C-function from generated code, align arguments on stack. + // After aligning the frame, non-register arguments must be stored in + // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments + // are word sized. + // Some compilers/platforms require the stack to be aligned when calling + // C++ code. + // Needs a scratch register to do some arithmetic. This register will be + // trashed. + void PrepareCallCFunction(int num_arguments, Register scratch); + + // Calls a C function and cleans up the space for arguments allocated + // by PrepareCallCFunction. The called function is not allowed to trigger a + // garbage collection, since that might move the code and invalidate the + // return address (unless this is somehow accounted for by the called + // function). + void CallCFunction(ExternalReference function, int num_arguments); + void CallCFunction(Register function, int num_arguments); + // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& builtin); diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc index 0015f780ed..beb6bf12de 100644 --- a/src/arm/regexp-macro-assembler-arm.cc +++ b/src/arm/regexp-macro-assembler-arm.cc @@ -163,7 +163,7 @@ void RegExpMacroAssemblerARM::Backtrack() { CheckPreemption(); // Pop Code* offset from backtrack stack, add Code* and jump to location. Pop(r0); - __ add(pc, r0, Operand(r5)); + __ add(pc, r0, Operand(code_pointer())); } @@ -338,7 +338,7 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase( } else { ASSERT(mode_ == UC16); int argument_count = 3; - FrameAlign(argument_count, r2); + __ PrepareCallCFunction(argument_count, r2); // r0 - offset of start of capture // r1 - length of capture @@ -360,7 +360,7 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase( ExternalReference function = ExternalReference::re_case_insensitive_compare_uc16(); - CallCFunction(function, argument_count); + __ CallCFunction(function, argument_count); // Check if function returned non-zero for success or zero for failure. __ cmp(r0, Operand(0)); @@ -770,12 +770,12 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { // Call GrowStack(backtrack_stackpointer()) static const int num_arguments = 2; - FrameAlign(num_arguments, r0); + __ PrepareCallCFunction(num_arguments, r0); __ mov(r0, backtrack_stackpointer()); __ add(r1, frame_pointer(), Operand(kStackHighEnd)); ExternalReference grow_stack = ExternalReference::re_grow_stack(); - CallCFunction(grow_stack, num_arguments); + __ CallCFunction(grow_stack, num_arguments); // If return NULL, we have failed to grow the stack, and // must exit with a stack-overflow exception. __ cmp(r0, Operand(0)); @@ -971,7 +971,7 @@ void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) { static const int num_arguments = 3; - FrameAlign(num_arguments, scratch); + __ PrepareCallCFunction(num_arguments, scratch); // RegExp code frame pointer. __ mov(r2, frame_pointer()); // Code* of self. @@ -1183,47 +1183,12 @@ int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() { } -void RegExpMacroAssemblerARM::FrameAlign(int num_arguments, Register scratch) { - int frameAlignment = OS::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 != 0) { - // 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)); - __ str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); - } else { - __ sub(sp, sp, Operand(stack_passed_arguments * kPointerSize)); - } -} - - -void RegExpMacroAssemblerARM::CallCFunction(ExternalReference function, - int num_arguments) { - __ mov(r5, Operand(function)); - // Just call directly. The function called cannot cause a GC, or - // allow preemption, so the return address in the link register - // stays correct. - __ Call(r5); - int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4; - if (OS::ActivationFrameAlignment() > kIntSize) { - __ ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); - } else { - __ add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); - } - __ mov(code_pointer(), Operand(masm_->CodeObject())); -} - - void RegExpMacroAssemblerARM::CallCFunctionUsingStub( ExternalReference function, int num_arguments) { // Must pass all arguments in registers. The stub pushes on the stack. ASSERT(num_arguments <= 4); - __ mov(r5, Operand(function)); + __ mov(code_pointer(), Operand(function)); RegExpCEntryStub stub; __ CallStub(&stub); if (OS::ActivationFrameAlignment() != 0) { diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h index 7de5f93d73..ef54388029 100644 --- a/src/arm/regexp-macro-assembler-arm.h +++ b/src/arm/regexp-macro-assembler-arm.h @@ -206,22 +206,6 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { // and increments it by a word size. inline void Pop(Register target); - // Before calling a C-function from generated code, align arguments on stack. - // After aligning the frame, non-register arguments must be stored in - // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments - // are word sized. - // Some compilers/platforms require the stack to be aligned when calling - // C++ code. - // Needs a scratch register to do some arithmetic. This register will be - // trashed. - inline void FrameAlign(int num_arguments, Register scratch); - - // Calls a C function and cleans up the space for arguments allocated - // by FrameAlign. The called function is not allowed to trigger a garbage - // collection. - inline void CallCFunction(ExternalReference function, - int num_arguments); - // Calls a C function and cleans up the frame alignment done by // by FrameAlign. The called function *is* allowed to trigger a garbage // collection, but may not take more than four arguments (no arguments