/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "calling_convention_mips64.h"
#include "base/logging.h"
#include "handle_scope-inl.h"
#include "utils/mips64/managed_register_mips64.h"
namespace art {
namespace mips64 {
static const GpuRegister kGpuArgumentRegisters[] = {
A0, A1, A2, A3, A4, A5, A6, A7
};
static const FpuRegister kFpuArgumentRegisters[] = {
F12, F13, F14, F15, F16, F17, F18, F19
};
// Calling convention
ManagedRegister Mips64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
return Mips64ManagedRegister::FromGpuRegister(T9);
}
ManagedRegister Mips64JniCallingConvention::InterproceduralScratchRegister() {
return Mips64ManagedRegister::FromGpuRegister(T9);
}
static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
if (shorty[0] == 'F' || shorty[0] == 'D') {
return Mips64ManagedRegister::FromFpuRegister(F0);
} else if (shorty[0] == 'V') {
return Mips64ManagedRegister::NoRegister();
} else {
return Mips64ManagedRegister::FromGpuRegister(V0);
}
}
ManagedRegister Mips64ManagedRuntimeCallingConvention::ReturnRegister() {
return ReturnRegisterForShorty(GetShorty());
}
ManagedRegister Mips64JniCallingConvention::ReturnRegister() {
return ReturnRegisterForShorty(GetShorty());
}
ManagedRegister Mips64JniCallingConvention::IntReturnRegister() {
return Mips64ManagedRegister::FromGpuRegister(V0);
}
// Managed runtime calling convention
ManagedRegister Mips64ManagedRuntimeCallingConvention::MethodRegister() {
return Mips64ManagedRegister::FromGpuRegister(A0);
}
bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
return false; // Everything moved to stack on entry.
}
bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
return true;
}
ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() {
LOG(FATAL) << "Should not reach here";
return ManagedRegister::NoRegister();
}
FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
CHECK(IsCurrentParamOnStack());
FrameOffset result =
FrameOffset(displacement_.Int32Value() + // displacement
kFramePointerSize + // Method ref
(itr_slots_ * sizeof(uint32_t))); // offset into in args
return result;
}
const ManagedRegisterEntrySpills& Mips64ManagedRuntimeCallingConvention::EntrySpills() {
// We spill the argument registers on MIPS64 to free them up for scratch use,
// we then assume all arguments are on the stack.
if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
int reg_index = 1; // we start from A1, A0 holds ArtMethod*.
// We need to choose the correct register size since the managed
// stack uses 32bit stack slots.
ResetIterator(FrameOffset(0));
while (HasNext()) {
if (reg_index < 8) {
if (IsCurrentParamAFloatOrDouble()) { // FP regs.
FpuRegister arg = kFpuArgumentRegisters[reg_index];
Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(arg);
entry_spills_.push_back(reg, IsCurrentParamADouble() ? 8 : 4);
} else { // GP regs.
GpuRegister arg = kGpuArgumentRegisters[reg_index];
Mips64ManagedRegister reg = Mips64ManagedRegister::FromGpuRegister(arg);
entry_spills_.push_back(reg,
(IsCurrentParamALong() && (!IsCurrentParamAReference())) ? 8 : 4);
}
// e.g. A1, A2, F3, A4, F5, F6, A7
reg_index++;
}
Next();
}
}
return entry_spills_;
}
// JNI calling convention
Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static, bool is_synchronized,
const char* shorty)
: JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S2));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S3));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S4));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S5));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S6));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S7));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(GP));
callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S8));
}
uint32_t Mips64JniCallingConvention::CoreSpillMask() const {
// Compute spill mask to agree with callee saves initialized in the constructor
uint32_t result = 0;
result = 1 << S2 | 1 << S3 | 1 << S4 | 1 << S5 | 1 << S6 | 1 << S7 | 1 << GP | 1 << S8 | 1 << RA;
return result;
}
ManagedRegister Mips64JniCallingConvention::ReturnScratchRegister() const {
return Mips64ManagedRegister::FromGpuRegister(AT);
}
size_t Mips64JniCallingConvention::FrameSize() {
// Mehtod* and callee save area size, local reference segment state
size_t frame_data_size = kFramePointerSize +
CalleeSaveRegisters().size() * kFramePointerSize + sizeof(uint32_t);
// References plus 2 words for HandleScope header
size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
// Plus return value spill area size
return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
}
size_t Mips64JniCallingConvention::OutArgSize() {
return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
}
bool Mips64JniCallingConvention::IsCurrentParamInRegister() {
return itr_args_ < 8;
}
bool Mips64JniCallingConvention::IsCurrentParamOnStack() {
return !IsCurrentParamInRegister();
}
ManagedRegister Mips64JniCallingConvention::CurrentParamRegister() {
CHECK(IsCurrentParamInRegister());
if (IsCurrentParamAFloatOrDouble()) {
return Mips64ManagedRegister::FromFpuRegister(kFpuArgumentRegisters[itr_args_]);
} else {
return Mips64ManagedRegister::FromGpuRegister(kGpuArgumentRegisters[itr_args_]);
}
}
FrameOffset Mips64JniCallingConvention::CurrentParamStackOffset() {
CHECK(IsCurrentParamOnStack());
size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_args_ - 8) * kFramePointerSize);
CHECK_LT(offset, OutArgSize());
return FrameOffset(offset);
}
size_t Mips64JniCallingConvention::NumberOfOutgoingStackArgs() {
// all arguments including JNI args
size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni();
// Nothing on the stack unless there are more than 8 arguments
return (all_args > 8) ? all_args - 8 : 0;
}
} // namespace mips64
} // namespace art