Fixes to make jni_compiler_test work on MIPS.
Fixed the jni compiler in numerous ways:
- Added NOP for delay slot of branches/jumps
- Made calling convention match registers pushed by stubs
- Fixes to assembly and added noreorder directive
Change-Id: I32bc55985fbbc58b5b5358149766b8738b3ac955
diff --git a/src/oat/jni/jni_compiler.cc b/src/oat/jni/jni_compiler.cc
index 7b710c5..585d60e 100644
--- a/src/oat/jni/jni_compiler.cc
+++ b/src/oat/jni/jni_compiler.cc
@@ -288,6 +288,11 @@
// 11. Save return value
FrameOffset return_save_location = main_jni_conv->ReturnValueSaveLocation();
if (main_jni_conv->SizeOfReturnValue() != 0 && !reference_return) {
+ if (instruction_set == kMips && main_jni_conv->GetReturnType() == Primitive::kPrimDouble &&
+ return_save_location.Uint32Value() % 8 != 0) {
+ // Ensure doubles are 8-byte aligned for MIPS
+ return_save_location = FrameOffset(return_save_location.Uint32Value() + kPointerSize);
+ }
CHECK_LT(return_save_location.Uint32Value(), frame_size+main_out_arg_size);
__ Store(return_save_location, main_jni_conv->ReturnRegister(), main_jni_conv->SizeOfReturnValue());
}
diff --git a/src/oat/jni/mips/calling_convention_mips.cc b/src/oat/jni/mips/calling_convention_mips.cc
index 09cc16d..606c05a 100644
--- a/src/oat/jni/mips/calling_convention_mips.cc
+++ b/src/oat/jni/mips/calling_convention_mips.cc
@@ -59,7 +59,7 @@
// Managed runtime calling convention
ManagedRegister MipsManagedRuntimeCallingConvention::MethodRegister() {
- return MipsManagedRegister::FromCoreRegister(V0);
+ return MipsManagedRegister::FromCoreRegister(A0);
}
bool MipsManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
@@ -107,7 +107,7 @@
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 r2.
+ // 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)) {
@@ -198,7 +198,7 @@
FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() {
CHECK_GE(itr_slots_, 4u);
- size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_slots_ - 4) * kPointerSize);
+ size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kPointerSize);
CHECK_LT(offset, OutArgSize());
return FrameOffset(offset);
}
@@ -207,8 +207,8 @@
size_t static_args = IsStatic() ? 1 : 0; // count jclass
// regular argument parameters and this
size_t param_args = NumArgs() + NumLongOrDoubleArgs();
- // count JNIEnv* less arguments in registers
- return static_args + param_args + 1 - 4;
+ // count JNIEnv*
+ return static_args + param_args + 1;
}
} // namespace mips
} // namespace art
diff --git a/src/oat/jni/mips/jni_internal_mips.cc b/src/oat/jni/mips/jni_internal_mips.cc
index ea2d7a1..6021cc1 100644
--- a/src/oat/jni/mips/jni_internal_mips.cc
+++ b/src/oat/jni/mips/jni_internal_mips.cc
@@ -73,6 +73,9 @@
reg_bytes = num_arg_array_bytes;
}
+ // Method* at bottom of frame is null thereby terminating managed stack crawls
+ __ StoreToOffset(kStoreWord, ZERO, SP, 0);
+
// Copy values onto the stack.
size_t src_offset = 0;
size_t dst_offset = (is_static ? 1 : 2) * kPointerSize;
@@ -131,7 +134,7 @@
// If the method returns a value, store it to the result pointer.
if (shorty[0] != 'V') {
// Load the result JValue pointer of the stub caller's out args.
- __ LoadFromOffset(kLoadWord, T9, SP, frame_size);
+ __ LoadFromOffset(kLoadWord, T9, SP, frame_size + 16);
switch (shorty[0]) {
case 'D':
__ StoreDToOffset(D0, T9, 0);
diff --git a/src/oat/runtime/mips/context_mips.cc b/src/oat/runtime/mips/context_mips.cc
index 1a4cb5d..dc13c63 100644
--- a/src/oat/runtime/mips/context_mips.cc
+++ b/src/oat/runtime/mips/context_mips.cc
@@ -30,7 +30,6 @@
for (int i = 0; i < 32; i++) {
fprs_[i] = kBadGprBase + i;
}
- pc_ = 0xEBAD601F;
#endif
}
@@ -56,7 +55,7 @@
int j = 1;
for (int i = 0; i < 32; i++) {
if (((fp_core_spills >> i) & 1) != 0) {
- fprs_[i] = fr.LoadCalleeSave(spill_count +fp_spill_count - j, frame_size);
+ fprs_[i] = fr.LoadCalleeSave(spill_count + fp_spill_count - j, frame_size);
j++;
}
}
@@ -69,7 +68,6 @@
gprs_[A1] = kBadGprBase + A1;
gprs_[A2] = kBadGprBase + A2;
gprs_[A3] = kBadGprBase + A3;
- gprs_[RA] = kBadGprBase + RA;
}
extern "C" void art_do_long_jump(uint32_t*, uint32_t*);
diff --git a/src/oat/runtime/mips/context_mips.h b/src/oat/runtime/mips/context_mips.h
index da4fc6a..1a86ca3 100644
--- a/src/oat/runtime/mips/context_mips.h
+++ b/src/oat/runtime/mips/context_mips.h
@@ -36,7 +36,7 @@
}
virtual void SetPC(uintptr_t new_pc) {
- pc_ = new_pc;
+ gprs_[RA] = new_pc;
}
virtual uintptr_t GetGPR(uint32_t reg) {
@@ -51,7 +51,6 @@
private:
uintptr_t gprs_[32];
uint32_t fprs_[32];
- uintptr_t pc_;
};
} // namespace mips
} // namespace art
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 6946825..2f7d120 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -16,6 +16,7 @@
#include "asm_support.h"
+ .set noreorder
.balign 4
/* Deliver the given exception */
@@ -31,10 +32,10 @@
/*
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveAll)
- * callee-save: $s0-$s8 + $ra, 10 total + 2 words
+ * callee-save: $s2-$s8 + $ra, 8 total + 2 words
*/
.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
- addiu $sp, $sp, 48
+ addiu $sp, $sp, -48
sw $ra, 44($sp)
sw $s8, 40($sp)
sw $s7, 36($sp)
@@ -43,9 +44,7 @@
sw $s4, 24($sp)
sw $s3, 20($sp)
sw $s2, 16($sp)
- sw $s1, 12($sp)
- sw $s0, 8($sp)
- # 2 open words, bottom will hold Method*
+ # 4 open words, bottom will hold Method*
.endm
/*
@@ -55,7 +54,7 @@
* callee-save: $s2-$s8 + $ra, 8 total + 4 words
*/
.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
- addiu $sp, $sp, 48
+ addiu $sp, $sp, -48
sw $ra, 44($sp)
sw $s8, 40($sp)
sw $s7, 36($sp)
@@ -84,7 +83,7 @@
* $a1-$a3, $s2-$s8, $ra, 11 total + 1
*/
.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
- addiu $sp, $sp, 48
+ addiu $sp, $sp, -48
sw $ra, 44($sp)
sw $s8, 40($sp)
sw $s7, 36($sp)
@@ -945,8 +944,10 @@
ALIGN_FUNCTION_ENTRY
art_indexof:
jr $ra
+ nop
.global art_string_compareto
ALIGN_FUNCTION_ENTRY
art_string_compareto:
jr $ra
+ nop
diff --git a/src/oat/runtime/mips/stub_mips.cc b/src/oat/runtime/mips/stub_mips.cc
index 8ab3f8d..4865c59 100644
--- a/src/oat/runtime/mips/stub_mips.cc
+++ b/src/oat/runtime/mips/stub_mips.cc
@@ -131,36 +131,20 @@
UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
#if !defined(ART_USE_LLVM_COMPILER)
// Save callee saves and ready frame for exception delivery
- __ AddConstant(SP, SP, -176);
- __ StoreToOffset(kStoreWord, RA, SP, 172);
- __ StoreToOffset(kStoreWord, T9, SP, 168);
- __ StoreToOffset(kStoreWord, T8, SP, 164);
- __ StoreToOffset(kStoreWord, T7, SP, 160);
- __ StoreToOffset(kStoreWord, T6, SP, 156);
- __ StoreToOffset(kStoreWord, T5, SP, 152);
- __ StoreToOffset(kStoreWord, T4, SP, 148);
- __ StoreToOffset(kStoreWord, T3, SP, 144);
- __ StoreToOffset(kStoreWord, T2, SP, 140);
- __ StoreToOffset(kStoreWord, T1, SP, 136);
- __ StoreToOffset(kStoreWord, T0, SP, 132);
- __ StoreDToOffset(D15, SP, 124);
- __ StoreDToOffset(D14, SP, 116);
- __ StoreDToOffset(D13, SP, 108);
- __ StoreDToOffset(D12, SP, 100);
- __ StoreDToOffset(D11, SP, 92);
- __ StoreDToOffset(D10, SP, 84);
- __ StoreDToOffset(D9, SP, 76);
- __ StoreDToOffset(D8, SP, 68);
- __ StoreDToOffset(D7, SP, 60);
- __ StoreDToOffset(D6, SP, 52);
- __ StoreDToOffset(D5, SP, 44);
- __ StoreDToOffset(D4, SP, 36);
- __ StoreDToOffset(D3, SP, 28);
- __ StoreDToOffset(D2, SP, 20);
- __ StoreDToOffset(D1, SP, 12);
- __ StoreDToOffset(D0, SP, 4);
+ __ AddConstant(SP, SP, -48);
+ __ StoreToOffset(kStoreWord, RA, SP, 44);
+ __ StoreToOffset(kStoreWord, T9, SP, 40);
+ __ StoreToOffset(kStoreWord, T8, SP, 36);
+ __ StoreToOffset(kStoreWord, T7, SP, 32);
+ __ StoreToOffset(kStoreWord, T6, SP, 28);
+ __ StoreToOffset(kStoreWord, T5, SP, 24);
+ __ StoreToOffset(kStoreWord, T4, SP, 20);
+ __ StoreToOffset(kStoreWord, T3, SP, 16);
+ __ StoreToOffset(kStoreWord, T2, SP, 12);
+ __ StoreToOffset(kStoreWord, T1, SP, 8);
+ __ StoreToOffset(kStoreWord, T0, SP, 4);
- // R0 is the Method* already
+ // A0 is the Method* already
__ Move(A1, S1); // Pass Thread::Current() in A1
__ Move(A2, SP); // Pass SP in A2
// Call to throw AbstractMethodError
diff --git a/src/oat/utils/mips/assembler_mips.cc b/src/oat/utils/mips/assembler_mips.cc
index e164241..be1aceb 100644
--- a/src/oat/utils/mips/assembler_mips.cc
+++ b/src/oat/utils/mips/assembler_mips.cc
@@ -349,26 +349,32 @@
void MipsAssembler::Beq(Register rt, Register rs, uint16_t imm16) {
EmitI(0x4, rs, rt, imm16);
+ Nop();
}
void MipsAssembler::Bne(Register rt, Register rs, uint16_t imm16) {
EmitI(0x5, rs, rt, imm16);
+ Nop();
}
void MipsAssembler::J(uint32_t address) {
EmitJ(0x2, address);
+ Nop();
}
void MipsAssembler::Jal(uint32_t address) {
EmitJ(0x2, address);
+ Nop();
}
void MipsAssembler::Jr(Register rs) {
EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x08);
+ Nop();
}
void MipsAssembler::Jalr(Register rs) {
- EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x09);
+ EmitR(0, rs, static_cast<Register>(0), RA, 0, 0x09);
+ Nop();
}
void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
@@ -445,6 +451,10 @@
static_cast<Register>(0), 0, 0xD);
}
+void MipsAssembler::Nop() {
+ EmitR(0x0, static_cast<Register>(0), static_cast<Register>(0), static_cast<Register>(0), 0, 0x0);
+}
+
void MipsAssembler::Move(Register rt, Register rs) {
EmitI(0x8, rs, rt, 0);
}
@@ -604,6 +614,9 @@
// Decrease frame to required size.
DecreaseFrameSize(frame_size);
+
+ // Then jump to the return address.
+ Jr(RA);
}
void MipsAssembler::IncreaseFrameSize(size_t adjust) {
diff --git a/src/oat/utils/mips/assembler_mips.h b/src/oat/utils/mips/assembler_mips.h
index 8483e39..73937aa 100644
--- a/src/oat/utils/mips/assembler_mips.h
+++ b/src/oat/utils/mips/assembler_mips.h
@@ -296,6 +296,7 @@
void Sdc1(DRegister ft, Register rs, uint16_t imm16);
void Break();
+ void Nop();
void Move(Register rt, Register rs);
void Clear(Register rt);
void Not(Register rt, Register rs);
diff --git a/src/oat/utils/mips/managed_register_mips.cc b/src/oat/utils/mips/managed_register_mips.cc
index b48c959..195dafb 100644
--- a/src/oat/utils/mips/managed_register_mips.cc
+++ b/src/oat/utils/mips/managed_register_mips.cc
@@ -69,9 +69,9 @@
low = (r * 2) + kNumberOfCoreRegIds; // Return an FRegister.
} else {
CHECK(IsRegisterPair());
- low = (r - kNumberOfDRegIds) * 2; // Return a Register.
- if (low > 24) {
- // we got a pair higher than T8_T9, must be the dalvik special case
+ low = (r - kNumberOfDRegIds) * 2 + 2; // Return a Register.
+ if (low >= 24) {
+ // we got a pair higher than S6_S7, must be the dalvik special case
low = 5;
}
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 9983c7d..b4dfcfe 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1009,27 +1009,13 @@
(1 << art::mips::S5) | (1 << art::mips::S6) | (1 << art::mips::S7) |
(1 << art::mips::FP);
uint32_t arg_spills = (1 << art::mips::A1) | (1 << art::mips::A2) | (1 << art::mips::A3);
- uint32_t all_spills = (1 << art::mips::S1) | (1 << art::mips::SP);
uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
- (type == kSaveAll ? all_spills : 0) | (1 << art::mips::RA);
- uint32_t fp_all_spills = (1 << art::mips::F0) | (1 << art::mips::F1) | (1 << art::mips::F2) |
- (1 << art::mips::F3) | (1 << art::mips::F4) | (1 << art::mips::F5) |
- (1 << art::mips::F6) | (1 << art::mips::F7) | (1 << art::mips::F8) |
- (1 << art::mips::F9) | (1 << art::mips::F10) | (1 << art::mips::F11) |
- (1 << art::mips::F12) | (1 << art::mips::F13) | (1 << art::mips::F14) |
- (1 << art::mips::F15) | (1 << art::mips::F16) | (1 << art::mips::F17) |
- (1 << art::mips::F18) | (1 << art::mips::F19) | (1 << art::mips::F20) |
- (1 << art::mips::F21) | (1 << art::mips::F22) | (1 << art::mips::F23) |
- (1 << art::mips::F24) | (1 << art::mips::F25) | (1 << art::mips::F26) |
- (1 << art::mips::F27) | (1 << art::mips::F28) | (1 << art::mips::F29) |
- (1 << art::mips::F30) | (1 << art::mips::F31);
- uint32_t fp_spills = type == kSaveAll ? fp_all_spills : 0;
+ (1 << art::mips::RA);
size_t frame_size = RoundUp((__builtin_popcount(core_spills) /* gprs */ +
- __builtin_popcount(fp_spills) /* fprs */ +
1 /* Method* */) * kPointerSize, kStackAlignment);
method->SetFrameSizeInBytes(frame_size);
method->SetCoreSpillMask(core_spills);
- method->SetFpSpillMask(fp_spills);
+ method->SetFpSpillMask(0);
} else if (instruction_set == kX86) {
uint32_t ref_spills = (1 << art::x86::EBP) | (1 << art::x86::ESI) | (1 << art::x86::EDI);
uint32_t arg_spills = (1 << art::x86::ECX) | (1 << art::x86::EDX) | (1 << art::x86::EBX);
diff --git a/src/thread_mips.cc b/src/thread_mips.cc
index b3e6454..bc343ed 100644
--- a/src/thread_mips.cc
+++ b/src/thread_mips.cc
@@ -22,7 +22,7 @@
namespace art {
void Thread::InitCpu() {
- CHECK_EQ(THREAD_SUSPEND_COUNT_OFFSET, OFFSETOF_MEMBER(Thread, suspend_count_));
+ CHECK_EQ(THREAD_FLAGS_OFFSET, OFFSETOF_MEMBER(Thread, state_and_flags_));
CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_));
}