Move ABI-specific parts of forward interop to the separate file.
This commit is contained in:
committed by
Sergey Bogolepov
parent
bcaf986e3a
commit
094f113e06
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.native.interop.gen
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.native.interop.indexer.*
|
||||
|
||||
/**
|
||||
* objc_msgSend*_stret functions must be used when return value is returned through memory
|
||||
* pointed by implicit argument, which is passed on the register that would otherwise be used for receiver.
|
||||
*
|
||||
* The entire implementation is just the real ABI approximation which is enough for practical cases.
|
||||
*/
|
||||
internal fun Type.isStret(target: KonanTarget): Boolean {
|
||||
val unwrappedType = this.unwrapTypedefs()
|
||||
val abiInfo: ObjCAbiInfo = when (target) {
|
||||
KonanTarget.IOS_ARM64,
|
||||
KonanTarget.TVOS_ARM64 -> DarwinArm64AbiInfo()
|
||||
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.MACOS_X64,
|
||||
KonanTarget.WATCHOS_X64,
|
||||
KonanTarget.TVOS_X64 -> DarwinX64AbiInfo()
|
||||
|
||||
KonanTarget.WATCHOS_X86 -> DarwinX86AbiInfo()
|
||||
|
||||
KonanTarget.IOS_ARM32,
|
||||
KonanTarget.WATCHOS_ARM32 -> DarwinArm32AbiInfo(target)
|
||||
|
||||
else -> error("Cannot generate ObjC stubs for $target.")
|
||||
}
|
||||
return abiInfo.shouldUseStret(unwrappedType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides ABI-specific information about target for Objective C interop.
|
||||
*/
|
||||
interface ObjCAbiInfo {
|
||||
fun shouldUseStret(returnType: Type): Boolean
|
||||
}
|
||||
|
||||
class DarwinX64AbiInfo : ObjCAbiInfo {
|
||||
override fun shouldUseStret(returnType: Type): Boolean {
|
||||
return when (returnType) {
|
||||
is RecordType -> returnType.decl.def!!.size > 16 || returnType.hasUnalignedMembers()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DarwinX86AbiInfo : ObjCAbiInfo {
|
||||
override fun shouldUseStret(returnType: Type): Boolean {
|
||||
// https://github.com/llvm/llvm-project/blob/6c8a34ed9b49704bdd60838143047c62ba9f2502/clang/lib/CodeGen/TargetInfo.cpp#L1243
|
||||
return when (returnType) {
|
||||
is RecordType -> {
|
||||
val size = returnType.decl.def!!.size
|
||||
val canBePassedInRegisters = (size == 1L || size == 2L || size == 4L || size == 8L)
|
||||
return !canBePassedInRegisters
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DarwinArm32AbiInfo(private val target: KonanTarget) : ObjCAbiInfo {
|
||||
override fun shouldUseStret(returnType: Type): Boolean = when (target) {
|
||||
KonanTarget.IOS_ARM32 -> when (returnType) {
|
||||
is RecordType -> !returnType.isIntegerLikeType()
|
||||
else -> false
|
||||
}
|
||||
// 32-bit watchOS uses armv7k which is effectively Cortex-A7 and
|
||||
// uses AAPCS16 VPF.
|
||||
KonanTarget.WATCHOS_ARM32 -> when (returnType) {
|
||||
is RecordType -> {
|
||||
// https://github.com/llvm/llvm-project/blob/6c8a34ed9b49704bdd60838143047c62ba9f2502/clang/lib/CodeGen/TargetInfo.cpp#L6165
|
||||
when {
|
||||
returnType.decl.def!!.size <= 16 -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
else -> error("Unexpected target")
|
||||
}
|
||||
}
|
||||
|
||||
class DarwinArm64AbiInfo : ObjCAbiInfo {
|
||||
override fun shouldUseStret(returnType: Type): Boolean {
|
||||
// On aarch64 stret is never the case, since an implicit argument gets passed on x8.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun Type.isIntegerLikeType(): Boolean = when (this) {
|
||||
is RecordType -> {
|
||||
val def = this.decl.def
|
||||
if (def == null) {
|
||||
false
|
||||
} else {
|
||||
def.size <= 4 &&
|
||||
def.members.all {
|
||||
when (it) {
|
||||
is BitField -> it.type.isIntegerLikeType()
|
||||
is Field -> it.offset == 0L && it.type.isIntegerLikeType()
|
||||
is IncompleteField -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is ObjCPointer, is PointerType, CharType, is BoolType -> true
|
||||
is IntegerType -> this.size <= 4
|
||||
is Typedef -> this.def.aliased.isIntegerLikeType()
|
||||
is EnumType -> this.def.baseType.isIntegerLikeType()
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun Type.hasUnalignedMembers(): Boolean = when (this) {
|
||||
is Typedef -> this.def.aliased.hasUnalignedMembers()
|
||||
is RecordType -> this.decl.def!!.let { def ->
|
||||
def.fields.any {
|
||||
!it.isAligned ||
|
||||
// Check members of fields too:
|
||||
it.type.hasUnalignedMembers()
|
||||
}
|
||||
}
|
||||
is ArrayType -> this.elemType.hasUnalignedMembers()
|
||||
else -> false
|
||||
|
||||
// TODO: should the recursive checks be made in indexer when computing `hasUnalignedFields`?
|
||||
}
|
||||
-83
@@ -239,50 +239,6 @@ internal val ObjCContainer.classOrProtocol: ObjCClassOrProtocol
|
||||
is ObjCCategory -> this.clazz
|
||||
}
|
||||
|
||||
/**
|
||||
* objc_msgSend*_stret functions must be used when return value is returned through memory
|
||||
* pointed by implicit argument, which is passed on the register that would otherwise be used for receiver.
|
||||
*
|
||||
* The entire implementation is just the real ABI approximation which is enough for practical cases.
|
||||
*/
|
||||
internal fun Type.isStret(target: KonanTarget): Boolean {
|
||||
val unwrappedType = this.unwrapTypedefs()
|
||||
return when (target) {
|
||||
KonanTarget.IOS_ARM64,
|
||||
KonanTarget.TVOS_ARM64 ->
|
||||
false // On aarch64 stret is never the case, since an implicit argument gets passed on x8.
|
||||
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.MACOS_X64,
|
||||
KonanTarget.WATCHOS_X64,
|
||||
KonanTarget.TVOS_X64 -> when (unwrappedType) {
|
||||
is RecordType -> unwrappedType.decl.def!!.size > 16 || this.hasUnalignedMembers()
|
||||
else -> false
|
||||
}
|
||||
|
||||
// See: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW5
|
||||
// Structures 1 or 2 bytes in size are placed in EAX.
|
||||
// Structures 4 or 8 bytes in size are placed in: EAX and EDX.
|
||||
// Structures of other sizes are placed at the address supplied by the caller.
|
||||
KonanTarget.WATCHOS_X86 -> when (unwrappedType) {
|
||||
is RecordType -> {
|
||||
val size = unwrappedType.decl.def!!.size
|
||||
val canBePassedInRegisters = (size == 1L || size == 2L || size == 4L || size == 8L)
|
||||
return !canBePassedInRegisters
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
KonanTarget.IOS_ARM32,
|
||||
KonanTarget.WATCHOS_ARM32 -> when (unwrappedType) {
|
||||
is RecordType -> !this.isIntegerLikeType()
|
||||
else -> false
|
||||
}
|
||||
|
||||
else -> error("Cannot generate ObjC stubs for $target.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun deprecatedInit(className: String, initParameterNames: List<String>, factory: Boolean): AnnotationStub {
|
||||
val replacement = if (factory) "$className.create" else className
|
||||
val replacementKind = if (factory) "factory method" else "constructor"
|
||||
@@ -290,45 +246,6 @@ private fun deprecatedInit(className: String, initParameterNames: List<String>,
|
||||
return AnnotationStub.Deprecated("Use $replacementKind instead", replaceWith)
|
||||
}
|
||||
|
||||
private fun Type.isIntegerLikeType(): Boolean = when (this) {
|
||||
is RecordType -> {
|
||||
val def = this.decl.def
|
||||
if (def == null) {
|
||||
false
|
||||
} else {
|
||||
def.size <= 4 &&
|
||||
def.members.all {
|
||||
when (it) {
|
||||
is BitField -> it.type.isIntegerLikeType()
|
||||
is Field -> it.offset == 0L && it.type.isIntegerLikeType()
|
||||
is IncompleteField -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is ObjCPointer, is PointerType, CharType, is BoolType -> true
|
||||
is IntegerType -> this.size <= 4
|
||||
is Typedef -> this.def.aliased.isIntegerLikeType()
|
||||
is EnumType -> this.def.baseType.isIntegerLikeType()
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun Type.hasUnalignedMembers(): Boolean = when (this) {
|
||||
is Typedef -> this.def.aliased.hasUnalignedMembers()
|
||||
is RecordType -> this.decl.def!!.let { def ->
|
||||
def.fields.any {
|
||||
!it.isAligned ||
|
||||
// Check members of fields too:
|
||||
it.type.hasUnalignedMembers()
|
||||
}
|
||||
}
|
||||
is ArrayType -> this.elemType.hasUnalignedMembers()
|
||||
else -> false
|
||||
|
||||
// TODO: should the recursive checks be made in indexer when computing `hasUnalignedFields`?
|
||||
}
|
||||
|
||||
internal val ObjCMethod.kotlinName: String
|
||||
get() {
|
||||
val candidate = selector.split(":").first()
|
||||
|
||||
Reference in New Issue
Block a user