Commit 68a0a108 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

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
parent 67116752
......@@ -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);
}
......
......@@ -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),
......
......@@ -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);
......
......@@ -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<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> 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) {
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment