Rework Objective-C constructors and support 'initBy' intrinsic

This commit is contained in:
Svyatoslav Scherbina
2017-08-29 13:33:01 +03:00
committed by SvyatoslavScherbina
parent 5a7e3e20b4
commit 07f26dc1df
6 changed files with 65 additions and 7 deletions
@@ -51,8 +51,17 @@ class ObjCPointerHolder(inline val rawPtr: NativePtr) {
@konan.internal.ExportForCompiler
private external fun ObjCObject.initFromPtr(ptr: NativePtr)
@konan.internal.Intrinsic
external fun <T : ObjCObjectBase> T.initBy(constructorCall: T): T
@konan.internal.ExportForCompiler
private fun ObjCObject.initFrom(other: ObjCObject?) = this.initFromPtr(other!!.rawPtr)
private fun ObjCObjectBase.superInitCheck(superInitCallResult: ObjCObject?) {
if (superInitCallResult == null)
throw RuntimeException("Super initialization failed")
if (superInitCallResult.rawPtr != this.rawPtr)
throw UnsupportedOperationException("Super initializer has replaced object")
}
fun <T : Any?> Any?.uncheckedCast(): T = @Suppress("UNCHECKED_CAST") (this as T) // TODO: make private
@@ -421,7 +421,7 @@ val ObjCClassOrProtocol.kotlinName: String get() = when (this) {
}
private val ObjCClass.baseClassName: String
get() = baseClass?.name ?: "ObjCObject"
get() = baseClass?.name ?: "ObjCObjectBase"
private fun Parameter.getTypeStringRepresentation() =
(if (this.nsConsumed) "__attribute__((ns_consumed)) " else "") + type.getStringRepresentation()
@@ -135,7 +135,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
.getContributedDescriptors().filterIsInstance<PropertyDescriptor>().single()
val objCObjectInitFromPtr = packageScope.getContributedFunctions("initFromPtr").single()
val objCObjectInitFrom = packageScope.getContributedFunctions("initFrom").single()
val allocObjCObject = packageScope.getContributedFunctions("allocObjCObject").single()
@@ -155,6 +154,9 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
val interpretObjCPointerOrNull = packageScope.getContributedFunctions("interpretObjCPointerOrNull").single()
val interpretObjCPointer = packageScope.getContributedFunctions("interpretObjCPointer").single()
val objCObjectSuperInitCheck = packageScope.getContributedFunctions("superInitCheck").single()
val objCObjectInitBy = packageScope.getContributedFunctions("initBy").single()
val objCAction = packageScope.getContributedClassifier("ObjCAction") as ClassDescriptor
val objCOutlet = packageScope.getContributedClassifier("ObjCOutlet") as ClassDescriptor
@@ -56,7 +56,8 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val interopObjCObjectInitFromPtr =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectInitFromPtr)
val interopObjCObjectInitFrom = symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectInitFrom)
val interopObjCObjectSuperInitCheck =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectSuperInitCheck)
val interopObjCObjectRawValueGetter =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectRawPtr.getter!!)
@@ -1607,10 +1607,30 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return null
}
private fun evaluateSpecialIntrinsicCall(expression: IrFunctionAccessExpression): LLVMValueRef? {
if (expression.descriptor.isIntrinsic) {
when (expression.descriptor.original) {
context.interopBuiltIns.objCObjectInitBy -> {
val receiver = evaluateExpression(expression.extensionReceiver!!)
val irConstructorCall = expression.getValueArgument(0) as IrCall
val constructorDescriptor = irConstructorCall.descriptor as ClassConstructorDescriptor
val constructorArgs = evaluateExplicitArgs(irConstructorCall)
val args = listOf(receiver) + constructorArgs
callDirect(constructorDescriptor, args, Lifetime.IRRELEVANT)
return receiver
}
}
}
return null
}
//-------------------------------------------------------------------------//
private fun evaluateCall(value: IrMemberAccessExpression): LLVMValueRef {
private fun evaluateCall(value: IrFunctionAccessExpression): LLVMValueRef {
context.log{"evaluateCall : ${ir2string(value)}"}
evaluateSpecialIntrinsicCall(value)?.let { return it }
val args = evaluateExplicitArgs(value)
compileTimeEvaluate(value, args)?.let { return it }
@@ -1925,6 +1945,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert(args.isEmpty())
functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero,
lifetime = resultLifetime(callee))
} else if (constructedClass.isKotlinObjCClass()) {
callDirect(context.interopBuiltIns.allocObjCObject, listOf(genGetObjCClass(constructedClass)),
resultLifetime(callee))
} else {
functionGenerationContext.allocInstance(typeInfoForAllocation(constructedClass), resultLifetime(callee))
}
@@ -388,7 +388,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initCall = builder.genLoweredObjCMethodCall(
initMethodInfo,
superQualifier = symbolTable.referenceClass(expression.descriptor.constructedClass),
receiver = builder.callAlloc(constructedClass.symbol),
receiver = builder.irGet(constructedClass.thisReceiver!!.symbol),
arguments = initMethod.valueParameters.map { expression.getValueArgument(it)!! }
)
@@ -400,7 +400,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
// Required for the IR to be valid, will be ignored in codegen:
+IrDelegatingConstructorCallImpl(startOffset, endOffset, superConstructor, superConstructor.descriptor)
+irCall(symbols.interopObjCObjectInitFrom).apply {
+irCall(symbols.interopObjCObjectSuperInitCheck).apply {
extensionReceiver = irGet(constructedClass.thisReceiver!!.symbol)
putValueArgument(0, initCall)
}
@@ -729,6 +729,29 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
}
interop.objCObjectInitBy -> {
val intrinsic = interop.objCObjectInitBy.name
val argument = expression.getValueArgument(0)!!
val constructedClass =
((argument as? IrCall)?.descriptor as? ClassConstructorDescriptor)?.constructedClass
if (constructedClass == null) {
context.reportCompilationError("Argument of '$intrinsic' must be a constructor call",
irFile, argument)
}
val extensionReceiver = expression.extensionReceiver!!
if (extensionReceiver !is IrGetValue ||
extensionReceiver.descriptor != constructedClass.thisAsReceiverParameter) {
context.reportCompilationError("Receiver of '$intrinsic' must be a 'this' of the constructed class",
irFile, extensionReceiver)
}
expression
}
else -> expression
}
}