diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index f5d02d255e..ef04fab632 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -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 diff --git a/classpath/jni-util.h b/classpath/jni-util.h index 0ad6d9d636..f32a632adc 100644 --- a/classpath/jni-util.h +++ b/classpath/jni-util.h @@ -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 diff --git a/src/avian/arm.h b/src/avian/arm.h index ceed56e984..5743edcfdd 100644 --- a/src/avian/arm.h +++ b/src/avian/arm.h @@ -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(stack + *stackIndex)[*stackSubIndex] = argument; + advance(stackIndex, stackSubIndex, *stackSubIndex + 1); + break; + + case INT16_TYPE: + advance(stackIndex, stackSubIndex, pad(*stackSubIndex, 2)); + reinterpret_cast(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(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;