fix ARM64 iOS JNI crashes

As documented at
https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html,
the ARM64 iOS ABI differs from the generic ABI in a few important
ways.  Specifically, arguments passed via the stack are aligned
according to their natural alignment instead of 8 bytes.  The VM's
dynamic call code was aligning each argument to 8 bytes, so native JNI
code couldn't find them in their expected places.

Also, we weren't setting the "os.arch" system property on ARM64, so I
fixed that too.
This commit is contained in:
Joel Dice 2015-02-05 16:44:23 -07:00
parent a13e97ddf7
commit c2a0210c7b
3 changed files with 87 additions and 2 deletions

View File

@ -853,6 +853,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL
#elif defined ARCH_arm
e->SetObjectArrayElement(array, index++, e->NewStringUTF("os.arch=arm"));
#elif defined ARCH_arm64
e->SetObjectArrayElement(array, index++, e->NewStringUTF("os.arch=arm64"));
#else
#error "unknown architecture"
#endif
#ifdef PLATFORM_WINDOWS

View File

@ -72,6 +72,8 @@ typedef unsigned __int64 uint64_t;
#define ARCH_x86_64
#elif defined __arm__
#define ARCH_arm
#elif defined __aarch64__
#define ARCH_arm64
#endif
#endif // not _MSC_VER

View File

@ -199,6 +199,72 @@ inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
}
#endif
#if (defined __APPLE__) && (defined ARCH_arm64)
const bool AppleARM64 = true;
#else
const bool AppleARM64 = false;
#endif
inline void advance(unsigned* stackIndex,
unsigned* stackSubIndex,
unsigned newStackSubIndex)
{
if (AppleARM64) {
if (newStackSubIndex == BytesPerWord) {
*stackSubIndex = 0;
++(*stackIndex);
} else {
*stackSubIndex = newStackSubIndex;
}
}
}
inline void push(uint8_t type,
uintptr_t* stack,
unsigned* stackIndex,
unsigned* stackSubIndex,
uintptr_t argument)
{
if (AppleARM64) {
// See
// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
// for how Apple diverges from the generic ARM64 ABI on iOS.
// Specifically, arguments passed on the stack are aligned to
// their natural alignment rather than 8.
switch (type) {
case INT8_TYPE:
reinterpret_cast<int8_t*>(stack + *stackIndex)[*stackSubIndex] = argument;
advance(stackIndex, stackSubIndex, *stackSubIndex + 1);
break;
case INT16_TYPE:
advance(stackIndex, stackSubIndex, pad(*stackSubIndex, 2));
reinterpret_cast<int16_t*>(stack + *stackIndex)[*stackSubIndex / 2]
= argument;
advance(stackIndex, stackSubIndex, *stackSubIndex + 2);
break;
case INT32_TYPE:
case FLOAT_TYPE:
advance(stackIndex, stackSubIndex, pad(*stackSubIndex, 4));
reinterpret_cast<int32_t*>(stack + *stackIndex)[*stackSubIndex / 4]
= argument;
advance(stackIndex, stackSubIndex, *stackSubIndex + 4);
break;
case POINTER_TYPE:
advance(stackIndex, stackSubIndex, pad(*stackSubIndex));
stack[(*stackIndex)++] = argument;
break;
default:
abort();
}
} else {
stack[(*stackIndex)++] = argument;
}
}
inline uint64_t dynamicCall(void* function,
uintptr_t* arguments,
uint8_t* argumentTypes,
@ -226,6 +292,7 @@ inline uint64_t dynamicCall(void* function,
(argumentCount * 8)
/ BytesPerWord); // is > argumentSize to account for padding
unsigned stackIndex = 0;
unsigned stackSubIndex = 0;
unsigned ai = 0;
for (unsigned ati = 0; ati < argumentCount; ++ati) {
@ -242,6 +309,7 @@ inline uint64_t dynamicCall(void* function,
memcpy(vfpTable + vfpIndex, arguments + ai, 8);
vfpIndex += 8 / BytesPerWord;
} else {
advance(&stackIndex, &stackSubIndex, pad(stackSubIndex));
vfpIndex = VfpCount;
if (stackIndex % Alignment) {
++stackIndex;
@ -260,7 +328,11 @@ inline uint64_t dynamicCall(void* function,
} else if (vfpIndex < VfpCount) {
vfpTable[vfpIndex++] = arguments[ai];
} else {
RUNTIME_ARRAY_BODY(stack)[stackIndex++] = arguments[ai];
push(argumentTypes[ati],
RUNTIME_ARRAY_BODY(stack),
&stackIndex,
&stackSubIndex,
arguments[ai]);
}
++ai;
break;
@ -280,6 +352,7 @@ inline uint64_t dynamicCall(void* function,
gprIndex += 8 / BytesPerWord;
}
} else { // pass argument on stack
advance(&stackIndex, &stackSubIndex, pad(stackSubIndex));
gprIndex = GprCount;
if (stackIndex % Alignment) {
++stackIndex;
@ -295,7 +368,11 @@ inline uint64_t dynamicCall(void* function,
if (gprIndex < GprCount) {
gprTable[gprIndex++] = arguments[ai];
} else {
RUNTIME_ARRAY_BODY(stack)[stackIndex++] = arguments[ai];
push(argumentTypes[ati],
RUNTIME_ARRAY_BODY(stack),
&stackIndex,
&stackSubIndex,
arguments[ai]);
}
++ai;
} break;