summaryrefslogtreecommitdiffstats
path: root/compiler/jni/quick/mips/calling_convention_mips.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/jni/quick/mips/calling_convention_mips.cc')
-rw-r--r--compiler/jni/quick/mips/calling_convention_mips.cc215
1 files changed, 215 insertions, 0 deletions
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
new file mode 100644
index 0000000000..053ab44eb4
--- /dev/null
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 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_mips.h"
+
+#include "base/logging.h"
+#include "oat/utils/mips/managed_register_mips.h"
+
+namespace art {
+namespace mips {
+
+// Calling convention
+ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
+ return MipsManagedRegister::FromCoreRegister(T9);
+}
+
+ManagedRegister MipsJniCallingConvention::InterproceduralScratchRegister() {
+ return MipsManagedRegister::FromCoreRegister(T9);
+}
+
+static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
+ if (shorty[0] == 'F') {
+ return MipsManagedRegister::FromFRegister(F0);
+ } else if (shorty[0] == 'D') {
+ return MipsManagedRegister::FromDRegister(D0);
+ } else if (shorty[0] == 'J') {
+ return MipsManagedRegister::FromRegisterPair(V0_V1);
+ } else if (shorty[0] == 'V') {
+ return MipsManagedRegister::NoRegister();
+ } else {
+ return MipsManagedRegister::FromCoreRegister(V0);
+ }
+}
+
+ManagedRegister MipsManagedRuntimeCallingConvention::ReturnRegister() {
+ return ReturnRegisterForShorty(GetShorty());
+}
+
+ManagedRegister MipsJniCallingConvention::ReturnRegister() {
+ return ReturnRegisterForShorty(GetShorty());
+}
+
+ManagedRegister MipsJniCallingConvention::IntReturnRegister() {
+ return MipsManagedRegister::FromCoreRegister(V0);
+}
+
+// Managed runtime calling convention
+
+ManagedRegister MipsManagedRuntimeCallingConvention::MethodRegister() {
+ return MipsManagedRegister::FromCoreRegister(A0);
+}
+
+bool MipsManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
+ return false; // Everything moved to stack on entry.
+}
+
+bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
+ return true;
+}
+
+ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() {
+ LOG(FATAL) << "Should not reach here";
+ return ManagedRegister::NoRegister();
+}
+
+FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() {
+ CHECK(IsCurrentParamOnStack());
+ FrameOffset result =
+ FrameOffset(displacement_.Int32Value() + // displacement
+ kPointerSize + // Method*
+ (itr_slots_ * kPointerSize)); // offset into in args
+ return result;
+}
+
+const std::vector<ManagedRegister>& MipsManagedRuntimeCallingConvention::EntrySpills() {
+ // We spill the argument registers on MIPS to free them up for scratch use, we then assume
+ // all arguments are on the stack.
+ if (entry_spills_.size() == 0) {
+ size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
+ if (num_spills > 0) {
+ entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A1));
+ if (num_spills > 1) {
+ entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A2));
+ if (num_spills > 2) {
+ entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A3));
+ }
+ }
+ }
+ }
+ return entry_spills_;
+}
+// JNI calling convention
+
+MipsJniCallingConvention::MipsJniCallingConvention(bool is_static, bool is_synchronized,
+ const char* shorty)
+ : JniCallingConvention(is_static, is_synchronized, shorty) {
+ // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
+ // or jclass for static methods and the JNIEnv. We start at the aligned register A2.
+ size_t padding = 0;
+ for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
+ if (IsParamALongOrDouble(cur_arg)) {
+ if ((cur_reg & 1) != 0) {
+ padding += 4;
+ cur_reg++; // additional bump to ensure alignment
+ }
+ cur_reg++; // additional bump to skip extra long word
+ }
+ cur_reg++; // bump the iterator for every argument
+ }
+ padding_ = padding;
+
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T0));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T1));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T2));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T3));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T4));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T5));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T6));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T7));
+ callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T8));
+}
+
+uint32_t MipsJniCallingConvention::CoreSpillMask() const {
+ // Compute spill mask to agree with callee saves initialized in the constructor
+ uint32_t result = 0;
+ result = 1 << T0 | 1 << T1 | 1 << T2 | 1 << T3 | 1 << T4 | 1 << T5 | 1 << T6 |
+ 1 << T7 | 1 << T8 | 1 << RA;
+ return result;
+}
+
+ManagedRegister MipsJniCallingConvention::ReturnScratchRegister() const {
+ return MipsManagedRegister::FromCoreRegister(AT);
+}
+
+size_t MipsJniCallingConvention::FrameSize() {
+ // Method*, LR and callee save area size, local reference segment state
+ size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kPointerSize;
+ // References plus 2 words for SIRT header
+ size_t sirt_size = (ReferenceCount() + 2) * kPointerSize;
+ // Plus return value spill area size
+ return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
+}
+
+size_t MipsJniCallingConvention::OutArgSize() {
+ return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize + padding_,
+ kStackAlignment);
+}
+
+// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
+// in even register numbers and stack slots
+void MipsJniCallingConvention::Next() {
+ JniCallingConvention::Next();
+ size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
+ if ((itr_args_ >= 2) &&
+ (arg_pos < NumArgs()) &&
+ IsParamALongOrDouble(arg_pos)) {
+ // itr_slots_ needs to be an even number, according to AAPCS.
+ if ((itr_slots_ & 0x1u) != 0) {
+ itr_slots_++;
+ }
+ }
+}
+
+bool MipsJniCallingConvention::IsCurrentParamInRegister() {
+ return itr_slots_ < 4;
+}
+
+bool MipsJniCallingConvention::IsCurrentParamOnStack() {
+ return !IsCurrentParamInRegister();
+}
+
+static const Register kJniArgumentRegisters[] = {
+ A0, A1, A2, A3
+};
+ManagedRegister MipsJniCallingConvention::CurrentParamRegister() {
+ CHECK_LT(itr_slots_, 4u);
+ int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
+ if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
+ CHECK_EQ(itr_slots_, 2u);
+ return MipsManagedRegister::FromRegisterPair(A2_A3);
+ } else {
+ return
+ MipsManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
+ }
+}
+
+FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() {
+ CHECK_GE(itr_slots_, 4u);
+ size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kPointerSize);
+ CHECK_LT(offset, OutArgSize());
+ return FrameOffset(offset);
+}
+
+size_t MipsJniCallingConvention::NumberOfOutgoingStackArgs() {
+ size_t static_args = IsStatic() ? 1 : 0; // count jclass
+ // regular argument parameters and this
+ size_t param_args = NumArgs() + NumLongOrDoubleArgs();
+ // count JNIEnv*
+ return static_args + param_args + 1;
+}
+} // namespace mips
+} // namespace art