ObjCExport: don't use autorelease when sending arguments to Swift/Obj-C
This commit is contained in:
committed by
Space
parent
9326978327
commit
085e2448cd
-8
@@ -48,14 +48,6 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
))
|
||||
|
||||
val objcAutorelease = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"llvm.objc.autorelease",
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
))
|
||||
|
||||
val objcAutoreleaseReturnValue = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"llvm.objc.autoreleaseReturnValue",
|
||||
LlvmRetType(int8TypePtr),
|
||||
|
||||
+10
-4
@@ -34,10 +34,6 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||
LlvmFunctionSignature(invokeMethod, codegen),
|
||||
"invokeFunction${bridge.nameSuffix}"
|
||||
).generate {
|
||||
val args = (0 until bridge.numberOfParameters).map { index ->
|
||||
kotlinReferenceToLocalObjC(param(index + 1))
|
||||
}
|
||||
|
||||
val thisRef = param(0)
|
||||
val associatedObjectHolder = if (useSeparateHolder) {
|
||||
val bodyPtr = bitcast(pointerType(bodyType), thisRef)
|
||||
@@ -51,10 +47,20 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||
)
|
||||
|
||||
val invoke = loadBlockInvoke(blockPtr, bridge)
|
||||
|
||||
val args = (0 until bridge.numberOfParameters).map { index ->
|
||||
kotlinReferenceToRetainedObjC(param(index + 1))
|
||||
}
|
||||
|
||||
switchThreadStateIfExperimentalMM(ThreadState.Native)
|
||||
// Using terminatingExceptionHandler, so any exception thrown by `invoke` will lead to the termination,
|
||||
// and switching the thread state back to `Runnable` on exceptional path is not required.
|
||||
val result = call(invoke, listOf(blockPtr) + args, exceptionHandler = terminatingExceptionHandler)
|
||||
|
||||
args.forEach {
|
||||
objcReleaseFromNativeThreadState(it)
|
||||
}
|
||||
|
||||
switchThreadStateIfExperimentalMM(ThreadState.Runnable)
|
||||
|
||||
val kotlinResult = if (bridge.returnsVoid) {
|
||||
|
||||
+33
-23
@@ -87,9 +87,13 @@ internal class ObjCExportFunctionGenerationContext(
|
||||
|
||||
fun objcReleaseFromRunnableThreadState(objCReference: LLVMValueRef) {
|
||||
switchThreadStateIfExperimentalMM(ThreadState.Native)
|
||||
objcReleaseFromNativeThreadState(objCReference)
|
||||
switchThreadStateIfExperimentalMM(ThreadState.Runnable)
|
||||
}
|
||||
|
||||
fun objcReleaseFromNativeThreadState(objCReference: LLVMValueRef) {
|
||||
// It is nounwind, so no exception handler is required.
|
||||
call(objCExportCodegen.objcRelease, listOf(objCReference), exceptionHandler = ExceptionHandler.None)
|
||||
switchThreadStateIfExperimentalMM(ThreadState.Runnable)
|
||||
}
|
||||
|
||||
override fun processReturns() {
|
||||
@@ -300,29 +304,11 @@ internal class ObjCExportCodeGenerator(
|
||||
resultLifetime
|
||||
)
|
||||
|
||||
private fun ObjCExportFunctionGenerationContext.kotlinFunctionToObjCBlockPointer(
|
||||
typeBridge: BlockPointerBridge,
|
||||
value: LLVMValueRef
|
||||
) = callFromBridge(objcAutorelease, listOf(kotlinFunctionToRetainedObjCBlockPointer(typeBridge, value)))
|
||||
|
||||
internal fun ObjCExportFunctionGenerationContext.kotlinFunctionToRetainedObjCBlockPointer(
|
||||
typeBridge: BlockPointerBridge,
|
||||
value: LLVMValueRef
|
||||
) = callFromBridge(kotlinFunctionToRetainedBlockConverter(typeBridge), listOf(value))
|
||||
|
||||
fun ObjCExportFunctionGenerationContext.kotlinToLocalObjC(
|
||||
value: LLVMValueRef,
|
||||
typeBridge: TypeBridge
|
||||
): LLVMValueRef = if (LLVMTypeOf(value) == voidType) {
|
||||
typeBridge.makeNothing()
|
||||
} else {
|
||||
when (typeBridge) {
|
||||
is ReferenceBridge -> kotlinReferenceToLocalObjC(value)
|
||||
is BlockPointerBridge -> kotlinFunctionToObjCBlockPointer(typeBridge, value) // TODO: use stack-allocated block here.
|
||||
is ValueTypeBridge -> kotlinToObjC(value, typeBridge.objCValueType)
|
||||
}
|
||||
}
|
||||
|
||||
fun ObjCExportFunctionGenerationContext.objCToKotlin(
|
||||
value: LLVMValueRef,
|
||||
typeBridge: TypeBridge,
|
||||
@@ -1184,6 +1170,8 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
parameterDescriptor to param(index)
|
||||
}.toMap()
|
||||
|
||||
val objCReferenceArgsToRelease = mutableListOf<LLVMValueRef>()
|
||||
|
||||
val objCArgs = methodBridge.parametersAssociated(irFunction).map { (bridge, parameter) ->
|
||||
when (bridge) {
|
||||
is MethodBridgeValueParameter.Mapped -> {
|
||||
@@ -1194,10 +1182,26 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
expectedType = parameterToBase[parameter]!!.type,
|
||||
resultLifetime = Lifetime.ARGUMENT
|
||||
)
|
||||
kotlinToLocalObjC(kotlinValue, bridge.bridge)
|
||||
if (LLVMTypeOf(kotlinValue) == voidType) {
|
||||
bridge.bridge.makeNothing()
|
||||
} else {
|
||||
when (bridge.bridge) {
|
||||
is ReferenceBridge -> kotlinReferenceToRetainedObjC(kotlinValue).also { objCReferenceArgsToRelease += it }
|
||||
is BlockPointerBridge -> kotlinFunctionToRetainedObjCBlockPointer(bridge.bridge, kotlinValue) // TODO: use stack-allocated block here.
|
||||
.also { objCReferenceArgsToRelease += it }
|
||||
is ValueTypeBridge -> kotlinToObjC(kotlinValue, bridge.bridge.objCValueType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MethodBridgeReceiver.Instance -> kotlinReferenceToLocalObjC(parameters[parameter]!!)
|
||||
MethodBridgeReceiver.Instance -> {
|
||||
// `kotlinReferenceToLocalObjC` can add the result to autoreleasepool in some cases. But not here.
|
||||
// Because this `parameter` is the receiver of a bridge in an Obj-C/Swift class extending
|
||||
// Kotlin class or interface.
|
||||
// So `kotlinReferenceToLocalObjC` here just unwraps the Obj-C reference
|
||||
// without using autoreleasepool or any other reference counting operations.
|
||||
kotlinReferenceToLocalObjC(parameters[parameter]!!)
|
||||
}
|
||||
MethodBridgeSelector -> {
|
||||
val selector = baseMethod.selector
|
||||
// Selector is referenced thus should be defined to avoid false positive non-public API rejection:
|
||||
@@ -1224,13 +1228,14 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
Lifetime.ARGUMENT
|
||||
)
|
||||
|
||||
// TODO: use stack-allocated block here instead.
|
||||
val converter = if (bridge.useUnitCompletion) {
|
||||
unitContinuationToRetainedCompletionConverter
|
||||
} else {
|
||||
continuationToRetainedCompletionConverter
|
||||
}
|
||||
val retainedCompletion = callFromBridge(converter, listOf(intercepted))
|
||||
callFromBridge(objcAutorelease, listOf(retainedCompletion)) // TODO: use stack-allocated block here instead.
|
||||
callFromBridge(converter, listOf(intercepted))
|
||||
.also { objCReferenceArgsToRelease += it }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1239,6 +1244,11 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
// Using terminatingExceptionHandler, so any exception thrown by the method will lead to the termination,
|
||||
// and switching the thread state back to `Runnable` on exceptional path is not required.
|
||||
val targetResult = call(objcMsgSend, objCArgs, exceptionHandler = terminatingExceptionHandler)
|
||||
|
||||
objCReferenceArgsToRelease.forEach {
|
||||
objcReleaseFromNativeThreadState(it)
|
||||
}
|
||||
|
||||
switchThreadStateIfExperimentalMM(ThreadState.Runnable)
|
||||
|
||||
assert(baseMethod.symbol !is IrConstructorSymbol)
|
||||
|
||||
@@ -1020,11 +1020,18 @@ __attribute__((swift_name("NoAutoreleaseSendHelper")))
|
||||
@protocol KtNoAutoreleaseSendHelper
|
||||
@required
|
||||
- (void)sendKotlinObjectKotlinObject:(KtKotlinObject *)kotlinObject __attribute__((swift_name("sendKotlinObject(kotlinObject:)")));
|
||||
- (void (^)(KtKotlinObject *))blockReceivingKotlinObject __attribute__((swift_name("blockReceivingKotlinObject()")));
|
||||
- (void)sendSwiftObjectSwiftObject:(id)swiftObject __attribute__((swift_name("sendSwiftObject(swiftObject:)")));
|
||||
- (void)sendListList:(NSArray<id> *)list __attribute__((swift_name("sendList(list:)")));
|
||||
- (void)sendStringString:(NSString *)string __attribute__((swift_name("sendString(string:)")));
|
||||
- (void)sendNumberNumber:(id)number __attribute__((swift_name("sendNumber(number:)")));
|
||||
- (void)sendBlockBlock:(KtKotlinObject *(^)(void))block __attribute__((swift_name("sendBlock(block:)")));
|
||||
|
||||
/**
|
||||
@note This method converts instances of CancellationException to errors.
|
||||
Other uncaught Kotlin exceptions are fatal.
|
||||
*/
|
||||
- (void)sendCompletionWithCompletionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("sendCompletion(completionHandler:)")));
|
||||
@end;
|
||||
|
||||
__attribute__((swift_name("NoAutoreleaseReceiveHelper")))
|
||||
@@ -1043,11 +1050,18 @@ __attribute__((swift_name("NoAutoreleaseKotlinSendHelper")))
|
||||
@interface KtNoAutoreleaseKotlinSendHelper : KtBase <KtNoAutoreleaseSendHelper>
|
||||
- (instancetype)initWithKotlinLivenessTracker:(KtKotlinLivenessTracker *)kotlinLivenessTracker __attribute__((swift_name("init(kotlinLivenessTracker:)"))) __attribute__((objc_designated_initializer));
|
||||
- (void)sendKotlinObjectKotlinObject:(KtKotlinObject *)kotlinObject __attribute__((swift_name("sendKotlinObject(kotlinObject:)")));
|
||||
- (void (^)(KtKotlinObject *))blockReceivingKotlinObject __attribute__((swift_name("blockReceivingKotlinObject()")));
|
||||
- (void)sendSwiftObjectSwiftObject:(id)swiftObject __attribute__((swift_name("sendSwiftObject(swiftObject:)")));
|
||||
- (void)sendListList:(NSArray<id> *)list __attribute__((swift_name("sendList(list:)")));
|
||||
- (void)sendStringString:(NSString *)string __attribute__((swift_name("sendString(string:)")));
|
||||
- (void)sendNumberNumber:(id)number __attribute__((swift_name("sendNumber(number:)")));
|
||||
- (void)sendBlockBlock:(KtKotlinObject *(^)(void))block __attribute__((swift_name("sendBlock(block:)")));
|
||||
|
||||
/**
|
||||
@note This method converts instances of CancellationException to errors.
|
||||
Other uncaught Kotlin exceptions are fatal.
|
||||
*/
|
||||
- (void)sendCompletionWithCompletionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("sendCompletion(completionHandler:)")));
|
||||
@property (readonly) KtKotlinLivenessTracker *kotlinLivenessTracker __attribute__((swift_name("kotlinLivenessTracker")));
|
||||
@end;
|
||||
|
||||
@@ -1091,11 +1105,13 @@ __attribute__((swift_name("NoAutoreleaseKt")))
|
||||
@interface KtNoAutoreleaseKt : KtBase
|
||||
+ (void)gc __attribute__((swift_name("gc()")));
|
||||
+ (void)callSendKotlinObjectHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendKotlinObject(helper:tracker:)")));
|
||||
+ (void)sendKotlinObjectToBlockHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("sendKotlinObjectToBlock(helper:tracker:)")));
|
||||
+ (void)callSendSwiftObjectHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker swiftObject:(id)swiftObject __attribute__((swift_name("callSendSwiftObject(helper:tracker:swiftObject:)")));
|
||||
+ (void)callSendListHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendList(helper:tracker:)")));
|
||||
+ (void)callSendStringHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendString(helper:tracker:)")));
|
||||
+ (void)callSendNumberHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendNumber(helper:tracker:)")));
|
||||
+ (void)callSendBlockHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendBlock(helper:tracker:)")));
|
||||
+ (void)callSendCompletionHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendCompletion(helper:tracker:)")));
|
||||
+ (void)callReceiveKotlinObjectHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveKotlinObject(helper:tracker:)")));
|
||||
+ (void)callReceiveSwiftObjectHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveSwiftObject(helper:tracker:)")));
|
||||
+ (void)callReceiveListHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveList(helper:tracker:)")));
|
||||
|
||||
@@ -962,11 +962,18 @@ __attribute__((swift_name("NoAutoreleaseSendHelper")))
|
||||
@protocol KtNoAutoreleaseSendHelper
|
||||
@required
|
||||
- (void)sendKotlinObjectKotlinObject:(KtKotlinObject *)kotlinObject __attribute__((swift_name("sendKotlinObject(kotlinObject:)")));
|
||||
- (void (^)(KtKotlinObject *))blockReceivingKotlinObject __attribute__((swift_name("blockReceivingKotlinObject()")));
|
||||
- (void)sendSwiftObjectSwiftObject:(id)swiftObject __attribute__((swift_name("sendSwiftObject(swiftObject:)")));
|
||||
- (void)sendListList:(NSArray<id> *)list __attribute__((swift_name("sendList(list:)")));
|
||||
- (void)sendStringString:(NSString *)string __attribute__((swift_name("sendString(string:)")));
|
||||
- (void)sendNumberNumber:(id)number __attribute__((swift_name("sendNumber(number:)")));
|
||||
- (void)sendBlockBlock:(KtKotlinObject *(^)(void))block __attribute__((swift_name("sendBlock(block:)")));
|
||||
|
||||
/**
|
||||
@note This method converts instances of CancellationException to errors.
|
||||
Other uncaught Kotlin exceptions are fatal.
|
||||
*/
|
||||
- (void)sendCompletionWithCompletionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("sendCompletion(completionHandler:)")));
|
||||
@end;
|
||||
|
||||
__attribute__((swift_name("NoAutoreleaseReceiveHelper")))
|
||||
@@ -985,11 +992,18 @@ __attribute__((swift_name("NoAutoreleaseKotlinSendHelper")))
|
||||
@interface KtNoAutoreleaseKotlinSendHelper : KtBase <KtNoAutoreleaseSendHelper>
|
||||
- (instancetype)initWithKotlinLivenessTracker:(KtKotlinLivenessTracker *)kotlinLivenessTracker __attribute__((swift_name("init(kotlinLivenessTracker:)"))) __attribute__((objc_designated_initializer));
|
||||
- (void)sendKotlinObjectKotlinObject:(KtKotlinObject *)kotlinObject __attribute__((swift_name("sendKotlinObject(kotlinObject:)")));
|
||||
- (void (^)(KtKotlinObject *))blockReceivingKotlinObject __attribute__((swift_name("blockReceivingKotlinObject()")));
|
||||
- (void)sendSwiftObjectSwiftObject:(id)swiftObject __attribute__((swift_name("sendSwiftObject(swiftObject:)")));
|
||||
- (void)sendListList:(NSArray<id> *)list __attribute__((swift_name("sendList(list:)")));
|
||||
- (void)sendStringString:(NSString *)string __attribute__((swift_name("sendString(string:)")));
|
||||
- (void)sendNumberNumber:(id)number __attribute__((swift_name("sendNumber(number:)")));
|
||||
- (void)sendBlockBlock:(KtKotlinObject *(^)(void))block __attribute__((swift_name("sendBlock(block:)")));
|
||||
|
||||
/**
|
||||
@note This method converts instances of CancellationException to errors.
|
||||
Other uncaught Kotlin exceptions are fatal.
|
||||
*/
|
||||
- (void)sendCompletionWithCompletionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("sendCompletion(completionHandler:)")));
|
||||
@property (readonly) KtKotlinLivenessTracker *kotlinLivenessTracker __attribute__((swift_name("kotlinLivenessTracker")));
|
||||
@end;
|
||||
|
||||
@@ -1033,11 +1047,13 @@ __attribute__((swift_name("NoAutoreleaseKt")))
|
||||
@interface KtNoAutoreleaseKt : KtBase
|
||||
+ (void)gc __attribute__((swift_name("gc()")));
|
||||
+ (void)callSendKotlinObjectHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendKotlinObject(helper:tracker:)")));
|
||||
+ (void)sendKotlinObjectToBlockHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("sendKotlinObjectToBlock(helper:tracker:)")));
|
||||
+ (void)callSendSwiftObjectHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker swiftObject:(id)swiftObject __attribute__((swift_name("callSendSwiftObject(helper:tracker:swiftObject:)")));
|
||||
+ (void)callSendListHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendList(helper:tracker:)")));
|
||||
+ (void)callSendStringHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendString(helper:tracker:)")));
|
||||
+ (void)callSendNumberHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendNumber(helper:tracker:)")));
|
||||
+ (void)callSendBlockHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendBlock(helper:tracker:)")));
|
||||
+ (void)callSendCompletionHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendCompletion(helper:tracker:)")));
|
||||
+ (void)callReceiveKotlinObjectHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveKotlinObject(helper:tracker:)")));
|
||||
+ (void)callReceiveSwiftObjectHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveSwiftObject(helper:tracker:)")));
|
||||
+ (void)callReceiveListHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveList(helper:tracker:)")));
|
||||
|
||||
@@ -962,11 +962,18 @@ __attribute__((swift_name("NoAutoreleaseSendHelper")))
|
||||
@protocol KtNoAutoreleaseSendHelper
|
||||
@required
|
||||
- (void)sendKotlinObjectKotlinObject:(KtKotlinObject *)kotlinObject __attribute__((swift_name("sendKotlinObject(kotlinObject:)")));
|
||||
- (void (^)(KtKotlinObject *))blockReceivingKotlinObject __attribute__((swift_name("blockReceivingKotlinObject()")));
|
||||
- (void)sendSwiftObjectSwiftObject:(id)swiftObject __attribute__((swift_name("sendSwiftObject(swiftObject:)")));
|
||||
- (void)sendListList:(NSArray<id> *)list __attribute__((swift_name("sendList(list:)")));
|
||||
- (void)sendStringString:(NSString *)string __attribute__((swift_name("sendString(string:)")));
|
||||
- (void)sendNumberNumber:(id)number __attribute__((swift_name("sendNumber(number:)")));
|
||||
- (void)sendBlockBlock:(KtKotlinObject *(^)(void))block __attribute__((swift_name("sendBlock(block:)")));
|
||||
|
||||
/**
|
||||
@note This method converts instances of CancellationException to errors.
|
||||
Other uncaught Kotlin exceptions are fatal.
|
||||
*/
|
||||
- (void)sendCompletionWithCompletionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("sendCompletion(completionHandler:)")));
|
||||
@end;
|
||||
|
||||
__attribute__((swift_name("NoAutoreleaseReceiveHelper")))
|
||||
@@ -985,11 +992,18 @@ __attribute__((swift_name("NoAutoreleaseKotlinSendHelper")))
|
||||
@interface KtNoAutoreleaseKotlinSendHelper : KtBase <KtNoAutoreleaseSendHelper>
|
||||
- (instancetype)initWithKotlinLivenessTracker:(KtKotlinLivenessTracker *)kotlinLivenessTracker __attribute__((swift_name("init(kotlinLivenessTracker:)"))) __attribute__((objc_designated_initializer));
|
||||
- (void)sendKotlinObjectKotlinObject:(KtKotlinObject *)kotlinObject __attribute__((swift_name("sendKotlinObject(kotlinObject:)")));
|
||||
- (void (^)(KtKotlinObject *))blockReceivingKotlinObject __attribute__((swift_name("blockReceivingKotlinObject()")));
|
||||
- (void)sendSwiftObjectSwiftObject:(id)swiftObject __attribute__((swift_name("sendSwiftObject(swiftObject:)")));
|
||||
- (void)sendListList:(NSArray<id> *)list __attribute__((swift_name("sendList(list:)")));
|
||||
- (void)sendStringString:(NSString *)string __attribute__((swift_name("sendString(string:)")));
|
||||
- (void)sendNumberNumber:(id)number __attribute__((swift_name("sendNumber(number:)")));
|
||||
- (void)sendBlockBlock:(KtKotlinObject *(^)(void))block __attribute__((swift_name("sendBlock(block:)")));
|
||||
|
||||
/**
|
||||
@note This method converts instances of CancellationException to errors.
|
||||
Other uncaught Kotlin exceptions are fatal.
|
||||
*/
|
||||
- (void)sendCompletionWithCompletionHandler:(void (^)(id _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("sendCompletion(completionHandler:)")));
|
||||
@property (readonly) KtKotlinLivenessTracker *kotlinLivenessTracker __attribute__((swift_name("kotlinLivenessTracker")));
|
||||
@end;
|
||||
|
||||
@@ -1033,11 +1047,13 @@ __attribute__((swift_name("NoAutoreleaseKt")))
|
||||
@interface KtNoAutoreleaseKt : KtBase
|
||||
+ (void)gc __attribute__((swift_name("gc()")));
|
||||
+ (void)callSendKotlinObjectHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendKotlinObject(helper:tracker:)")));
|
||||
+ (void)sendKotlinObjectToBlockHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("sendKotlinObjectToBlock(helper:tracker:)")));
|
||||
+ (void)callSendSwiftObjectHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker swiftObject:(id)swiftObject __attribute__((swift_name("callSendSwiftObject(helper:tracker:swiftObject:)")));
|
||||
+ (void)callSendListHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendList(helper:tracker:)")));
|
||||
+ (void)callSendStringHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendString(helper:tracker:)")));
|
||||
+ (void)callSendNumberHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendNumber(helper:tracker:)")));
|
||||
+ (void)callSendBlockHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendBlock(helper:tracker:)")));
|
||||
+ (void)callSendCompletionHelper:(id<KtNoAutoreleaseSendHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callSendCompletion(helper:tracker:)")));
|
||||
+ (void)callReceiveKotlinObjectHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveKotlinObject(helper:tracker:)")));
|
||||
+ (void)callReceiveSwiftObjectHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveSwiftObject(helper:tracker:)")));
|
||||
+ (void)callReceiveListHelper:(id<KtNoAutoreleaseReceiveHelper>)helper tracker:(KtKotlinLivenessTracker *)tracker __attribute__((swift_name("callReceiveList(helper:tracker:)")));
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package noAutorelease
|
||||
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
import kotlin.native.internal.NativePtr
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlin.test.*
|
||||
@@ -23,11 +25,13 @@ class KotlinObject
|
||||
|
||||
interface NoAutoreleaseSendHelper {
|
||||
fun sendKotlinObject(kotlinObject: KotlinObject)
|
||||
fun blockReceivingKotlinObject(): (KotlinObject) -> Unit
|
||||
fun sendSwiftObject(swiftObject: Any)
|
||||
fun sendList(list: List<*>)
|
||||
fun sendString(string: String)
|
||||
fun sendNumber(number: Any)
|
||||
fun sendBlock(block: () -> KotlinObject)
|
||||
suspend fun sendCompletion(): Any?
|
||||
}
|
||||
|
||||
interface NoAutoreleaseReceiveHelper {
|
||||
@@ -41,11 +45,16 @@ interface NoAutoreleaseReceiveHelper {
|
||||
|
||||
class NoAutoreleaseKotlinSendHelper(val kotlinLivenessTracker: KotlinLivenessTracker) : NoAutoreleaseSendHelper {
|
||||
override fun sendKotlinObject(kotlinObject: KotlinObject) = kotlinLivenessTracker.add(kotlinObject)
|
||||
override fun blockReceivingKotlinObject(): (KotlinObject) -> Unit = { kotlinLivenessTracker.add(it) }
|
||||
override fun sendSwiftObject(swiftObject: Any) = kotlinLivenessTracker.add(swiftObject)
|
||||
override fun sendList(list: List<*>) = kotlinLivenessTracker.add(list)
|
||||
override fun sendString(string: String) = kotlinLivenessTracker.add(string)
|
||||
override fun sendNumber(number: Any) = kotlinLivenessTracker.add(number)
|
||||
override fun sendBlock(block: () -> KotlinObject) = kotlinLivenessTracker.add(block)
|
||||
override suspend fun sendCompletion() = suspendCoroutineUninterceptedOrReturn<Any?> { continuation ->
|
||||
kotlinLivenessTracker.add(continuation)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
class NoAutoreleaseKotlinReceiveHelper(val kotlinLivenessTracker: KotlinLivenessTracker) : NoAutoreleaseReceiveHelper {
|
||||
@@ -82,6 +91,14 @@ fun callSendKotlinObject(helper: NoAutoreleaseSendHelper, tracker: KotlinLivenes
|
||||
tracker.add(kotlinObject)
|
||||
}
|
||||
|
||||
fun sendKotlinObjectToBlock(helper: NoAutoreleaseSendHelper, tracker: KotlinLivenessTracker) {
|
||||
val kotlinObject = KotlinObject()
|
||||
|
||||
helper.blockReceivingKotlinObject()(kotlinObject)
|
||||
helper.blockReceivingKotlinObject()(kotlinObject)
|
||||
tracker.add(kotlinObject)
|
||||
}
|
||||
|
||||
fun callSendSwiftObject(helper: NoAutoreleaseSendHelper, tracker: KotlinLivenessTracker, swiftObject: Any) {
|
||||
helper.sendSwiftObject(swiftObject)
|
||||
helper.sendSwiftObject(swiftObject)
|
||||
@@ -120,6 +137,22 @@ fun callSendBlock(helper: NoAutoreleaseSendHelper, tracker: KotlinLivenessTracke
|
||||
tracker.add(block)
|
||||
}
|
||||
|
||||
private class EmptyContinuation : Continuation<Any?> {
|
||||
override val context: CoroutineContext = EmptyCoroutineContext
|
||||
override fun resumeWith(result: Result<Any?>) { result.getOrThrow() }
|
||||
}
|
||||
|
||||
fun callSendCompletion(helper: NoAutoreleaseSendHelper, tracker: KotlinLivenessTracker) {
|
||||
val completion = EmptyContinuation()
|
||||
|
||||
suspend {
|
||||
helper.sendCompletion()
|
||||
helper.sendCompletion()
|
||||
}.startCoroutine(completion)
|
||||
|
||||
tracker.add(completion)
|
||||
}
|
||||
|
||||
fun callReceiveKotlinObject(helper: NoAutoreleaseReceiveHelper, tracker: KotlinLivenessTracker) = repeat(2) {
|
||||
tracker.add(helper.receiveKotlinObject())
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@ private class NoAutoreleaseSwiftHelper : NoAutoreleaseSendHelper, NoAutoreleaseR
|
||||
swiftLivenessTracker.add(kotlinObject)
|
||||
}
|
||||
|
||||
func blockReceivingKotlinObject() -> (KotlinObject) -> Void {
|
||||
return {
|
||||
self.swiftLivenessTracker.add($0)
|
||||
}
|
||||
}
|
||||
|
||||
func sendSwiftObject(swiftObject: Any) {
|
||||
swiftLivenessTracker.add(swiftObject as AnyObject)
|
||||
}
|
||||
@@ -57,6 +63,10 @@ private class NoAutoreleaseSwiftHelper : NoAutoreleaseSendHelper, NoAutoreleaseR
|
||||
func sendBlock(block: @escaping () -> KotlinObject) {
|
||||
}
|
||||
|
||||
func sendCompletion(completionHandler: @escaping (Any?, Error?) -> Void) {
|
||||
completionHandler(nil, nil)
|
||||
}
|
||||
|
||||
let kotlinObject = KotlinObject()
|
||||
let swiftObject = SwiftObject2()
|
||||
let list = createList()
|
||||
@@ -220,6 +230,12 @@ private func testSendKotlinObjectToKotlin() throws {
|
||||
}
|
||||
}
|
||||
|
||||
private func testSendKotlinObjectToKotlinBlock() throws {
|
||||
try testSendToKotlin({ KotlinObject() }) {
|
||||
$0.blockReceivingKotlinObject()($1)
|
||||
}
|
||||
}
|
||||
|
||||
private func testSendSwiftObjectToKotlin() throws {
|
||||
try testSendToKotlin({ SwiftObject1() }) {
|
||||
$0.sendSwiftObject(swiftObject: $1)
|
||||
@@ -250,6 +266,12 @@ private func testSendBlockToKotlin() throws {
|
||||
}
|
||||
}
|
||||
|
||||
private func testSendCompletionToKotlin() throws {
|
||||
try testSendToKotlin({ createCompletion() }, flags: TestFlags(trackSwiftLifetime: false)) {
|
||||
$0.sendCompletion(completionHandler: $1)
|
||||
}
|
||||
}
|
||||
|
||||
private func testReceiveKotlinObjectFromKotlin() throws {
|
||||
try testReceiveFromKotlin {
|
||||
$0.receiveKotlinObject()
|
||||
@@ -328,6 +350,15 @@ private func testSendKotlinObjectToSwift() throws {
|
||||
}
|
||||
}
|
||||
|
||||
private func testSendKotlinObjectToSwiftBlock() throws {
|
||||
// Getting Swift block in Kotlin still adds it to the autoreleasepool.
|
||||
// The block is not our target, so just use `checkAutorelease: false` flag
|
||||
// to disable the relevant check for now.
|
||||
try testCallToSwift(flags: TestFlags(checkAutorelease: false)) {
|
||||
NoAutoreleaseKt.sendKotlinObjectToBlock(helper: $0, tracker: $1)
|
||||
}
|
||||
}
|
||||
|
||||
private func testSendSwiftObjectToSwift() throws {
|
||||
try testCallToSwift {
|
||||
NoAutoreleaseKt.callSendSwiftObject(helper: $0, tracker: $1, swiftObject: SwiftObject4())
|
||||
@@ -361,6 +392,12 @@ private func testSendBlockToSwift() throws {
|
||||
}
|
||||
}
|
||||
|
||||
private func testSendCompletionToSwift() throws {
|
||||
try testCallToSwift(flags: TestFlags(trackSwiftLifetime: false)) {
|
||||
NoAutoreleaseKt.callSendCompletion(helper: $0, tracker: $1)
|
||||
}
|
||||
}
|
||||
|
||||
private func testReceiveKotlinObjectFromSwift() throws {
|
||||
try testCallToSwift(flags: TestFlags(runGCTwice: true)) {
|
||||
NoAutoreleaseKt.callReceiveKotlinObject(helper: $0, tracker: $1)
|
||||
@@ -421,6 +458,10 @@ private func createBlock(swiftLivenessTracker: SwiftLivenessTracker) -> () -> Ko
|
||||
}
|
||||
}
|
||||
|
||||
private func createCompletion() -> (Any?, Error?) -> Void {
|
||||
return { _, _ in }
|
||||
}
|
||||
|
||||
private func createString() -> String {
|
||||
return NSObject().description // Make it dynamic.
|
||||
}
|
||||
@@ -434,11 +475,13 @@ class NoAutoreleaseTests : SimpleTestProvider {
|
||||
super.init()
|
||||
|
||||
test("testSendKotlinObjectToKotlin", testSendKotlinObjectToKotlin)
|
||||
test("testSendKotlinObjectToKotlinBlock", testSendKotlinObjectToKotlinBlock)
|
||||
test("testSendSwiftObjectToKotlin", testSendSwiftObjectToKotlin)
|
||||
test("testSendListToKotlin", testSendListToKotlin)
|
||||
test("testSendStringToKotlin", testSendStringToKotlin)
|
||||
test("testSendNumberToKotlin", testSendNumberToKotlin)
|
||||
test("testSendBlockToKotlin", testSendBlockToKotlin)
|
||||
test("testSendCompletionToKotlin", testSendCompletionToKotlin)
|
||||
|
||||
test("testReceiveKotlinObjectFromKotlin", testReceiveKotlinObjectFromKotlin)
|
||||
test("testReceiveSwiftObjectFromKotlin", testReceiveSwiftObjectFromKotlin)
|
||||
@@ -454,18 +497,16 @@ class NoAutoreleaseTests : SimpleTestProvider {
|
||||
test("testGetKotlinSingleton", testGetKotlinSingleton)
|
||||
test("testGetKotlinEnumEntry", testGetKotlinEnumEntry)
|
||||
|
||||
#if false
|
||||
test("testSendKotlinObjectToSwift", testSendKotlinObjectToSwift)
|
||||
#endif
|
||||
|
||||
test("testSendKotlinObjectToSwiftBlock", testSendKotlinObjectToSwiftBlock)
|
||||
test("testSendSwiftObjectToSwift", testSendSwiftObjectToSwift)
|
||||
|
||||
#if false
|
||||
test("testSendListToSwift", testSendListToSwift)
|
||||
test("testSendStringToSwift", testSendStringToSwift)
|
||||
test("testSendNumberToSwift", testSendNumberToSwift)
|
||||
test("testSendBlockToSwift", testSendBlockToSwift)
|
||||
test("testSendCompletionToSwift", testSendCompletionToSwift)
|
||||
|
||||
#if false
|
||||
test("testReceiveKotlinObjectFromSwift", testReceiveKotlinObjectFromSwift)
|
||||
test("testReceiveSwiftObjectFromSwift", testReceiveSwiftObjectFromSwift)
|
||||
test("testReceiveListFromSwift", testReceiveListFromSwift)
|
||||
|
||||
Reference in New Issue
Block a user