blob: 7e59fd5df01218048d0079aca0da7927c794e114 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
#ifndef ART_SRC_CALLING_CONVENTION_H_
#define ART_SRC_CALLING_CONVENTION_H_
#include <vector>
#include "managed_register.h"
#include "object.h"
#include "thread.h"
namespace art {
// Top-level abstraction for different calling conventions
class CallingConvention {
public:
CallingConvention* GetCallingConvention(Method* method);
bool IsReturnAReference() const { return method_->IsReturnAReference(); }
size_t SizeOfReturnValue() const { return method_->ReturnSize(); }
// Register that holds the incoming method argument
ManagedRegister MethodRegister();
// Register that holds result of this method
ManagedRegister ReturnRegister();
// Register reserved for scratch usage during procedure calls
ManagedRegister InterproceduralScratchRegister();
// Offset of Method within the frame
FrameOffset MethodStackOffset();
// Iterator interface
// Place iterator at start of arguments. The displacement is applied to
// frame offset methods to account for frames which may be on the stack
// below the one being iterated over.
void ResetIterator(FrameOffset displacement) {
displacement_ = displacement;
itr_slots_ = 0;
itr_args_ = 0;
itr_longs_and_doubles_ = 0;
}
protected:
explicit CallingConvention(Method* method) : displacement_(0),
method_(method) {}
const Method* GetMethod() const { return method_; }
// The slot number for current calling_convention argument.
// Note that each slot is 32-bit. When the current argument is bigger
// than 32 bits, return the first slot number for this argument.
unsigned int itr_slots_;
// The argument number along argument list for current argument
unsigned int itr_args_;
// Number of longs and doubles seen along argument list
unsigned int itr_longs_and_doubles_;
// Space for frames below this on the stack
FrameOffset displacement_;
private:
const Method* method_;
};
// Abstraction for managed code's calling conventions
class ManagedRuntimeCallingConvention : public CallingConvention {
public:
explicit ManagedRuntimeCallingConvention(Method* method) :
CallingConvention(method) {}
size_t FrameSize();
// Iterator interface
bool HasNext();
void Next();
bool IsCurrentParamAReference();
bool IsCurrentParamInRegister();
bool IsCurrentParamOnStack();
bool IsCurrentUserArg();
size_t CurrentParamSize();
ManagedRegister CurrentParamRegister();
FrameOffset CurrentParamStackOffset();
DISALLOW_COPY_AND_ASSIGN(ManagedRuntimeCallingConvention);
};
// Abstraction for JNI calling conventions
// | incoming stack args | <-- Prior SP
// | { Return address } | (x86)
// | { Return value spill } | (live on return slow paths)
// | { Stack Indirect Ref. |
// | Table... |
// | num. refs./link } | (here to prior SP is frame size)
// | { Spill area } | (ARM)
// | Method* | <-- Anchor SP written to thread
// | { Outgoing stack args |
// | ... } | <-- SP at point of call
// | Native frame |
class JniCallingConvention : public CallingConvention {
public:
explicit JniCallingConvention(Method* native_method) :
CallingConvention(native_method),
spill_regs_(ComputeRegsToSpillPreCall()) {}
// Size of frame excluding space for outgoing args (its assumed Method* is
// always at the bottom of a frame, but this doesn't work for outgoing
// native args). Includes alignment.
size_t FrameSize();
// Offset within the frame of the return pc
size_t ReturnPcOffset();
// Size of outgoing arguments, including alignment
size_t OutArgSize();
// Number of references in stack indirect reference table
size_t ReferenceCount();
// Size of area used to hold spilled registers
size_t SpillAreaSize();
// Location where the return value of a call can be squirreled if another
// call is made following the native call
FrameOffset ReturnValueSaveLocation();
// Registers that must be spilled (due to clobbering) before the call into
// the native routine
const std::vector<ManagedRegister>& RegsToSpillPreCall() {
return *spill_regs_.get();
}
// Returns true if the register will be clobbered by an outgoing
// argument value.
bool IsOutArgRegister(ManagedRegister reg);
// Iterator interface
bool HasNext();
void Next();
bool IsCurrentParamAReference();
bool IsCurrentParamInRegister();
bool IsCurrentParamOnStack();
size_t CurrentParamSize();
ManagedRegister CurrentParamRegister();
FrameOffset CurrentParamStackOffset();
// Iterator interface extension for JNI
FrameOffset CurrentParamSirtEntryOffset();
// Position of SIRT and interior fields
FrameOffset SirtOffset() {
return FrameOffset(displacement_.Int32Value() +
SpillAreaSize() +
kPointerSize); // above Method*
}
FrameOffset SirtNumRefsOffset() {
return FrameOffset(SirtOffset().Int32Value() +
StackIndirectReferenceTable::NumberOfReferencesOffset());
}
FrameOffset SirtLinkOffset() {
return FrameOffset(SirtOffset().Int32Value() +
StackIndirectReferenceTable::LinkOffset());
}
private:
// Named iterator positions
enum IteratorPos {
kJniEnv = 0,
kObjectOrClass = 1
};
// Number of stack slots for outgoing arguments, above which the SIRT is
// located
size_t NumberOfOutgoingStackArgs();
// Compute registers for RegsToSpillPreCall
std::vector<ManagedRegister>* ComputeRegsToSpillPreCall();
// Extra registers to spill before the call into native
const scoped_ptr<std::vector<ManagedRegister> > spill_regs_;
static size_t NumberOfExtraArgumentsForJni(const Method* method);
DISALLOW_COPY_AND_ASSIGN(JniCallingConvention);
};
} // namespace art
#endif // ART_SRC_CALLING_CONVENTION_H_