Make Objective-C objects shareable in Kotlin
This commit is contained in:
committed by
SvyatoslavScherbina
parent
df91304d54
commit
77897ba712
@@ -26,6 +26,7 @@ interface ObjCClassOf<T : ObjCObject> : ObjCClass // TODO: T should be added to
|
||||
typealias ObjCObjectMeta = ObjCClass
|
||||
|
||||
@ExportTypeInfo("theForeignObjCObjectTypeInfo")
|
||||
@kotlin.native.internal.Frozen
|
||||
internal open class ForeignObjCObject : kotlin.native.internal.ObjCObjectWrapper
|
||||
|
||||
abstract class ObjCObjectBase protected constructor() : ObjCObject {
|
||||
|
||||
+4
-2
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||
import org.jetbrains.kotlin.backend.konan.binaryTypeIsReference
|
||||
import org.jetbrains.kotlin.backend.konan.isObjCClass
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.isExported
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
||||
@@ -241,8 +242,9 @@ private val frozenAnnotation = FqName("kotlin.native.internal.Frozen")
|
||||
|
||||
internal val DeclarationDescriptor.isFrozen: Boolean
|
||||
get() = this.annotations.hasAnnotation(frozenAnnotation) ||
|
||||
// RTTI is used for non-reference type box:
|
||||
this is org.jetbrains.kotlin.descriptors.ClassDescriptor && !this.defaultType.binaryTypeIsReference()
|
||||
(this is org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
// RTTI is used for non-reference type box or Objective-C object wrapper:
|
||||
&& (!this.defaultType.binaryTypeIsReference() || this.isObjCClass()))
|
||||
|
||||
internal val FunctionDescriptor.isIntrinsic: Boolean
|
||||
get() = this.annotations.hasAnnotation(intrinsicAnnotation)
|
||||
|
||||
+6
-3
@@ -19,7 +19,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
private fun flagsFromClass(classDescriptor: ClassDescriptor): Int {
|
||||
var result = 0
|
||||
if (classDescriptor.isFrozen)
|
||||
result = result or 1 /* TF_IMMUTABLE */
|
||||
result = result or TF_IMMUTABLE
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -291,7 +291,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
// TODO: extract more code common with generate().
|
||||
fun generateSyntheticInterfaceImpl(
|
||||
descriptor: ClassDescriptor,
|
||||
methodImpls: Map<FunctionDescriptor, ConstPointer>
|
||||
methodImpls: Map<FunctionDescriptor, ConstPointer>,
|
||||
immutable: Boolean = false
|
||||
): ConstPointer {
|
||||
assert(descriptor.isInterface)
|
||||
|
||||
@@ -346,7 +347,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
fields = fieldsPtr, fieldsCount = fieldsCount,
|
||||
packageName = reflectionInfo.packageName,
|
||||
relativeName = reflectionInfo.relativeName,
|
||||
flags = flagsFromClass(descriptor),
|
||||
flags = flagsFromClass(descriptor) or (if (immutable) TF_IMMUTABLE else 0),
|
||||
extendedInfo = NullPointer(runtime.extendedTypeInfoType),
|
||||
writableTypeInfo = writableTypeInfo
|
||||
), vtable)
|
||||
@@ -376,3 +377,5 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val TF_IMMUTABLE = 1
|
||||
|
||||
+2
-1
@@ -403,7 +403,8 @@ private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberO
|
||||
|
||||
return rttiGenerator.generateSyntheticInterfaceImpl(
|
||||
irInterface,
|
||||
mapOf(invokeMethod to invokeImpl)
|
||||
mapOf(invokeMethod to invokeImpl),
|
||||
immutable = true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package conversions
|
||||
|
||||
import kotlin.native.concurrent.isFrozen
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@@ -236,3 +237,6 @@ fun IC2?.getValueOrNull2() = this?.value
|
||||
|
||||
fun IC3.getValue3() = value
|
||||
fun IC3?.getValueOrNull3() = this?.value
|
||||
|
||||
fun isFrozen(obj: Any): Boolean = obj.isFrozen
|
||||
fun kotlinLambda(block: (Any) -> Any): Any = block
|
||||
|
||||
@@ -420,6 +420,27 @@ func testInlineClasses() throws {
|
||||
try assertEquals(actual: ValuesKt.getValueOrNull3(ic3N), expected: nil)
|
||||
}
|
||||
|
||||
class TestSharedIImpl : NSObject, I {
|
||||
func iFun() -> String {
|
||||
return "TestSharedIImpl::iFun"
|
||||
}
|
||||
}
|
||||
|
||||
func testShared() throws {
|
||||
func assertFrozen(_ obj: AnyObject) throws {
|
||||
try assertTrue(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))")
|
||||
}
|
||||
|
||||
func assertNotFrozen(_ obj: AnyObject) throws {
|
||||
try assertFalse(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))")
|
||||
}
|
||||
|
||||
try assertFrozen(NSObject())
|
||||
try assertFrozen(TestSharedIImpl())
|
||||
try assertFrozen(ValuesKt.kotlinLambda(block: { return $0 }) as AnyObject)
|
||||
try assertNotFrozen(FinalClassExtOpen())
|
||||
}
|
||||
|
||||
// -------- Execution of the test --------
|
||||
|
||||
class ValuesTests : TestProvider {
|
||||
@@ -453,6 +474,7 @@ class ValuesTests : TestProvider {
|
||||
TestCase(name: "TestDataClass", method: withAutorelease(testDataClass)),
|
||||
TestCase(name: "TestCompanionObj", method: withAutorelease(testCompanionObj)),
|
||||
TestCase(name: "TestInlineClasses", method: withAutorelease(testInlineClasses)),
|
||||
TestCase(name: "TestShared", method: withAutorelease(testShared)),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,11 +669,16 @@ static const TypeInfo* createTypeInfo(
|
||||
TypeInfo* result = (TypeInfo*)konanAllocMemory(sizeof(TypeInfo) + vtable.size() * sizeof(void*));
|
||||
result->typeInfo_ = result;
|
||||
|
||||
result->flags_ = 0;
|
||||
|
||||
MakeGlobalHash(nullptr, 0, &result->name_);
|
||||
result->instanceSize_ = superType->instanceSize_;
|
||||
result->superType_ = superType;
|
||||
result->objOffsets_ = superType->objOffsets_;
|
||||
result->objOffsetsCount_ = superType->objOffsetsCount_;
|
||||
result->objOffsetsCount_ = superType->objOffsetsCount_; // So TF_IMMUTABLE can also be inherited:
|
||||
if ((superType->flags_ & TF_IMMUTABLE) != 0) {
|
||||
result->flags_ |= TF_IMMUTABLE;
|
||||
}
|
||||
|
||||
KStdVector<const TypeInfo*> implementedInterfaces(
|
||||
superType->implementedInterfaces_, superType->implementedInterfaces_ + superType->implementedInterfacesCount_
|
||||
|
||||
Reference in New Issue
Block a user