From 07f26dc1dfa8109fe6fff97bc0cebf2740ed38ee Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 29 Aug 2017 13:33:01 +0300 Subject: [PATCH] Rework Objective-C constructors and support 'initBy' intrinsic --- .../kotlin/kotlinx/cinterop/ObjectiveCImpl.kt | 11 +++++++- .../kotlin/native/interop/gen/ObjCStubs.kt | 2 +- .../kotlin/backend/konan/InteropUtils.kt | 4 ++- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 3 ++- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 25 ++++++++++++++++- .../backend/konan/lower/InteropLowering.kt | 27 +++++++++++++++++-- 6 files changed, 65 insertions(+), 7 deletions(-) diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt index 187926d5af0..7e96b5a4f9e 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt @@ -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.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 Any?.uncheckedCast(): T = @Suppress("UNCHECKED_CAST") (this as T) // TODO: make private diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt index e39dd188376..2213d2bdc52 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt @@ -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() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt index 42970fe6a15..754b4678702 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt @@ -135,7 +135,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) { .getContributedDescriptors().filterIsInstance().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 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index f5e4eb3c0b5..fdc3b510340 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -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!!) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 772abfa1e6b..e4ab36eb434 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1607,10 +1607,30 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { + 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 { + 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 } }