32-bit iOS support (#1708)

This commit is contained in:
Nikolay Igotti
2018-06-21 18:36:17 +03:00
committed by GitHub
parent 705f3ce438
commit 0da110a786
15 changed files with 108 additions and 47 deletions
@@ -187,7 +187,7 @@ internal class LinkStage(val context: Context) {
val framework = File(context.config.outputFile)
val dylibName = framework.name.removeSuffix(".framework")
val dylibRelativePath = when (target) {
KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 -> dylibName
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 -> dylibName
KonanTarget.MACOS_X64 -> "Versions/A/$dylibName"
else -> error(target)
}
@@ -96,7 +96,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
}
val objCDataGenerator = when (context.config.target) {
KonanTarget.IOS_ARM64, KonanTarget.IOS_X64, KonanTarget.MACOS_X64 -> ObjCDataGenerator(this)
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64,
KonanTarget.IOS_X64, KonanTarget.MACOS_X64 -> ObjCDataGenerator(this)
else -> null
}
@@ -451,6 +451,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
}
private val personalityFunctionName = when (target) {
KonanTarget.IOS_ARM32 -> "__gxx_personality_sj0"
KonanTarget.MINGW_X64 -> "__gxx_personality_seh0"
else -> "__gxx_personality_v0"
}
@@ -2253,9 +2253,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return if (bitsWithPaddingNum == 64) {
bits
} else if (bitsWithPaddingNum > 64) {
trunc(bits, kInt64)
trunc(bits, int64Type)
} else {
ext(bits, kInt64, signed)
ext(bits, int64Type, signed)
}
}
}
@@ -2268,7 +2268,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val size = extractConstUnsignedInt(args[2]).toInt()
val value = args[3]
assert(value.type == kInt64)
assert(value.type == int64Type)
val bitsType = LLVMIntType(size)!!
@@ -2350,6 +2350,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val isStret = when (context.config.target) {
KonanTarget.MACOS_X64, KonanTarget.IOS_X64 -> isLU // x86_64
KonanTarget.IOS_ARM64 -> false // aarch64
// TODO: what is the correct value?
KonanTarget.IOS_ARM32 -> false // armv7
else -> TODO()
}
@@ -122,6 +122,7 @@ internal val int1Type = LLVMInt1Type()!!
internal val int8Type = LLVMInt8Type()!!
internal val int16Type = LLVMInt16Type()!!
internal val int32Type = LLVMInt32Type()!!
internal val int64Type = LLVMInt64Type()!!
internal val int8TypePtr = pointerType(int8Type)
internal val voidType = LLVMVoidType()!!
@@ -142,7 +143,6 @@ internal val RuntimeAware.kTypeInfoPtr: LLVMTypeRef
get() = pointerType(kTypeInfo)
internal val kInt1 = LLVMInt1Type()!!
internal val kBoolean = kInt1
internal val kInt64 = LLVMInt64Type()!!
internal val kInt8Ptr = pointerType(int8Type)
internal val kInt8PtrPtr = pointerType(kInt8Ptr)
internal val kNullInt8Ptr = LLVMConstNull(kInt8Ptr)!!
@@ -100,6 +100,9 @@ internal class BlockAdapterToFunctionGenerator(val objCExportCodeGenerator: ObjC
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) =
if (is64Bit()) Int64(value) else Int32(value.toInt())
private fun generateDescriptorForBlockAdapterToFunction(numberOfParameters: Int): ConstValue {
val signature = buildString {
append('@')
@@ -116,11 +119,9 @@ internal class BlockAdapterToFunctionGenerator(val objCExportCodeGenerator: ObjC
}
}
assert(codegen.context.is64Bit())
return Struct(blockDescriptorType,
Int64(0),
Int64(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)),
codegen.context.LongInt(0L),
codegen.context.LongInt(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)),
constPointer(copyHelper),
constPointer(disposeHelper),
codegen.staticData.cStringLiteral(signature),
@@ -128,6 +129,8 @@ internal class BlockAdapterToFunctionGenerator(val objCExportCodeGenerator: ObjC
)
}
private fun FunctionGenerationContext.storeRefUnsafe(value: LLVMValueRef, slot: LLVMValueRef) {
assert(value.type == kObjHeaderPtr)
assert(slot.type == kObjHeaderPtrPtr)
@@ -450,7 +450,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
methodBridge: MethodBridge,
genBody: FunctionGenerationContext.() -> Unit
): LLVMValueRef {
val result = LLVMAddFunction(context.llvmModule, "", objCFunctionType(methodBridge))!!
val result = LLVMAddFunction(context.llvmModule, "", objCFunctionType(context, methodBridge))!!
generateFunction(codegen, result) {
genBody()
@@ -579,8 +579,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
tailrec fun genReturnValueOnSuccess(returnBridge: MethodBridge.ReturnValue): LLVMValueRef? = when (returnBridge) {
MethodBridge.ReturnValue.Void -> null
MethodBridge.ReturnValue.HashCode -> {
assert(codegen.context.is64Bit())
zext(targetResult!!, kInt64)
zext(targetResult!!, if (codegen.context.is64Bit()) int64Type else int32Type)
}
is MethodBridge.ReturnValue.Mapped -> kotlinToObjC(targetResult!!, returnBridge.bridge)
MethodBridge.ReturnValue.WithError.Success -> Int8(1).llvm // true
@@ -618,7 +617,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
val parameterToBase = descriptor.allParameters.zip(baseMethod.allParameters).toMap()
val objcMsgSend = msgSender(objCFunctionType(methodBridge))
val objcMsgSend = msgSender(objCFunctionType(context, methodBridge))
val functionType = codegen.getLlvmFunctionType(context.ir.get(descriptor))
@@ -679,10 +678,13 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
MethodBridge.ReturnValue.Void -> null
MethodBridge.ReturnValue.HashCode -> {
assert(codegen.context.is64Bit())
val low = trunc(targetResult, int32Type)
val high = trunc(shr(targetResult, 32, signed = false), int32Type)
xor(low, high)
if (codegen.context.is64Bit()) {
val low = trunc(targetResult, int32Type)
val high = trunc(shr(targetResult, 32, signed = false), int32Type)
xor(low, high)
} else {
trunc(targetResult, int32Type)
}
}
is MethodBridge.ReturnValue.Mapped -> {
@@ -1013,7 +1015,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
)
val encoding = getEncoding(methodBridge)
val imp = generateFunction(codegen, objCFunctionType(methodBridge), "") {
val imp = generateFunction(codegen, objCFunctionType(context, methodBridge), "") {
block()
}
@@ -1070,10 +1072,10 @@ private fun List<CallableMemberDescriptor>.toMethods(): List<FunctionDescriptor>
}
}
private fun objCFunctionType(methodBridge: MethodBridge): LLVMTypeRef {
private fun objCFunctionType(context: Context, methodBridge: MethodBridge): LLVMTypeRef {
val paramTypes = methodBridge.paramBridges.map { it.objCType }
val returnType = methodBridge.returnBridge.objCType
val returnType = methodBridge.returnBridge.objCType(context)
return functionType(returnType, false, *(paramTypes.toTypedArray()))
}
@@ -1084,7 +1086,7 @@ private val ObjCValueType.llvmType: LLVMTypeRef get() = when (this) {
ObjCValueType.UNSIGNED_SHORT -> int16Type
ObjCValueType.SHORT -> int16Type
ObjCValueType.INT -> int32Type
ObjCValueType.LONG_LONG -> kInt64
ObjCValueType.LONG_LONG -> int64Type
ObjCValueType.FLOAT -> LLVMFloatType()!!
ObjCValueType.DOUBLE -> LLVMDoubleType()!!
}
@@ -1097,15 +1099,17 @@ private val MethodBridgeParameter.objCType: LLVMTypeRef get() = when (this) {
is MethodBridgeValueParameter.KotlinResultOutParameter -> pointerType(this.bridge.objCType)
}
private val MethodBridge.ReturnValue.objCType: LLVMTypeRef get() = when (this) {
MethodBridge.ReturnValue.Void -> voidType
MethodBridge.ReturnValue.HashCode -> kInt64 // TODO: only for 64-bit platforms
is MethodBridge.ReturnValue.Mapped -> this.bridge.objCType
MethodBridge.ReturnValue.WithError.Success -> ObjCValueType.BOOL.llvmType
private fun MethodBridge.ReturnValue.objCType(context: Context): LLVMTypeRef {
return when (this) {
MethodBridge.ReturnValue.Void -> voidType
MethodBridge.ReturnValue.HashCode -> if (context.is64Bit()) int64Type else int32Type
is MethodBridge.ReturnValue.Mapped -> this.bridge.objCType
MethodBridge.ReturnValue.WithError.Success -> ObjCValueType.BOOL.llvmType
MethodBridge.ReturnValue.Instance.InitResult,
MethodBridge.ReturnValue.Instance.FactoryResult,
is MethodBridge.ReturnValue.WithError.RefOrNull -> ReferenceBridge.objCType
MethodBridge.ReturnValue.Instance.InitResult,
MethodBridge.ReturnValue.Instance.FactoryResult,
is MethodBridge.ReturnValue.WithError.RefOrNull -> ReferenceBridge.objCType
}
}
private val TypeBridge.objCType: LLVMTypeRef get() = when (this) {
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.AppleConfigurables
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -37,7 +38,7 @@ internal class ObjCExport(val codegen: CodeGenerator) {
private val target get() = context.config.target
internal fun produce() {
if (target != KonanTarget.IOS_ARM64 && target != KonanTarget.IOS_X64 && target != KonanTarget.MACOS_X64) return
if (target.family != Family.IOS && target.family != Family.OSX) return
if (!context.config.produce.isNativeBinary) return // TODO: emit RTTI to the same modules as classes belong to.
@@ -77,9 +78,9 @@ internal class ObjCExport(val codegen: CodeGenerator) {
headerGenerator.translateModule()
val framework = File(context.config.outputFile)
val frameworkContents = when (target) {
KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 -> framework
KonanTarget.MACOS_X64 -> framework.child("Versions/A")
val frameworkContents = when(target.family) {
Family.IOS -> framework
Family.OSX -> framework.child("Versions/A")
else -> error(target)
}
@@ -116,10 +117,9 @@ internal class ObjCExport(val codegen: CodeGenerator) {
}
private fun emitInfoPlist(frameworkContents: File, name: String) {
val directory = when (target) {
KonanTarget.IOS_ARM64,
KonanTarget.IOS_X64 -> frameworkContents
KonanTarget.MACOS_X64 -> frameworkContents.child("Resources").also { it.mkdirs() }
val directory = when {
target.family == Family.IOS -> frameworkContents
target == KonanTarget.MACOS_X64 -> frameworkContents.child("Resources").also { it.mkdirs() }
else -> error(target)
}
@@ -128,7 +128,7 @@ internal class ObjCExport(val codegen: CodeGenerator) {
val bundleId = pkg.child(Name.identifier(name)).asString()
val platform = when (target) {
KonanTarget.IOS_ARM64 -> "iPhoneOS"
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iPhoneOS"
KonanTarget.IOS_X64 -> "iPhoneSimulator"
KonanTarget.MACOS_X64 -> "MacOSX"
else -> error(target)
@@ -165,6 +165,7 @@ internal class ObjCExport(val codegen: CodeGenerator) {
contents.append(when (target) {
KonanTarget.IOS_ARM32,
KonanTarget.IOS_ARM64,
KonanTarget.IOS_X64 -> """
| <key>MinimumOSVersion</key>
@@ -191,6 +192,17 @@ internal class ObjCExport(val codegen: CodeGenerator) {
)
}
if (target == KonanTarget.IOS_ARM32) {
contents.append("""
| <key>UIRequiredDeviceCapabilities</key>
| <array>
| <string>armv7</string>
| </array>
""".trimMargin()
)
}
contents.append("""
</dict>
</plist>