Fix various JNI compiler bugs/unimplementeds.
For both x86 and arm we were under computing the outgoing argument size.
For ARM the managed double/long passing had been assumed to be following AAPCS,
however, currently we split long/doubles across R1_R2 and R3 and the stack.
Add support for this in the managed register and jni compiler code.
Add test and various other clean ups to jni compiler code.
Change-Id: I4129076d052a8bce42304f5331b71aa3ac50210f
diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc
index 78f0c6c..527ce5f 100644
--- a/src/calling_convention_arm.cc
+++ b/src/calling_convention_arm.cc
@@ -39,20 +39,25 @@
}
bool ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
- return !IsCurrentParamInRegister();
+ if (itr_slots_ < 2) {
+ return false;
+ } else if (itr_slots_ > 2) {
+ return true;
+ } else {
+ // handle funny case of a long/double straddling registers and the stack
+ return GetMethod()->IsParamALongOrDouble(itr_args_);
+ }
}
static const Register kManagedArgumentRegisters[] = {
R1, R2, R3
};
ManagedRegister ManagedRuntimeCallingConvention::CurrentParamRegister() {
- CHECK_LT(itr_slots_, 3u); // Otherwise, should have gone through stack
+ CHECK(IsCurrentParamInRegister());
const Method* method = GetMethod();
if (method->IsParamALongOrDouble(itr_args_)) {
if (itr_slots_ == 0) {
- // return R1 to denote R1_R2
- return ManagedRegister::FromCoreRegister(kManagedArgumentRegisters
- [itr_slots_]);
+ return ManagedRegister::FromRegisterPair(R1_R2);
} else if (itr_slots_ == 1) {
return ManagedRegister::FromRegisterPair(R2_R3);
} else {
@@ -67,10 +72,18 @@
}
FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
- CHECK_GE(itr_slots_, 3u);
- return FrameOffset(displacement_.Int32Value() + // displacement
- kPointerSize + // Method*
- (itr_slots_ * kPointerSize)); // offset into in args
+ CHECK(IsCurrentParamOnStack());
+ FrameOffset result =
+ FrameOffset(displacement_.Int32Value() + // displacement
+ kPointerSize + // Method*
+ (itr_slots_ * kPointerSize)); // offset into in args
+ if (itr_slots_ == 2) {
+ // the odd spanning case, bump the offset to skip the first half of the
+ // input which is in a register
+ CHECK(IsCurrentParamInRegister());
+ result = FrameOffset(result.Int32Value() + 4);
+ }
+ return result;
}
// JNI calling convention
@@ -85,6 +98,20 @@
kStackAlignment);
}
+size_t JniCallingConvention::OutArgSize() {
+ const Method* method = GetMethod();
+ size_t padding; // padding to ensure longs and doubles are not split in AAPCS
+ if (method->IsStatic()) {
+ padding = (method->NumArgs() > 1) && !method->IsParamALongOrDouble(0) &&
+ method->IsParamALongOrDouble(1) ? 4 : 0;
+ } else {
+ padding = (method->NumArgs() > 2) && !method->IsParamALongOrDouble(1) &&
+ method->IsParamALongOrDouble(2) ? 4 : 0;
+ }
+ return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize + padding,
+ kStackAlignment);
+}
+
size_t JniCallingConvention::ReturnPcOffset() {
// Link register is always the last value spilled, skip forward one word for
// the Method* then skip back one word to get the link register (ie +0)
@@ -160,7 +187,13 @@
}
size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
- return GetMethod()->NumArgs() + GetMethod()->NumLongOrDoubleArgs() - 2;
+ const Method* method = GetMethod();
+ size_t static_args = method->IsStatic() ? 1 : 0; // count jclass
+ // regular argument parameters and this
+ size_t param_args = method->NumArgs() +
+ method->NumLongOrDoubleArgs();
+ // count JNIEnv* less arguments in registers
+ return static_args + param_args + 1 - 4;
}
} // namespace art