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
This commit is contained in:
parent
67116752d9
commit
68a0a108c4
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user