Avoid requesting selectors in Objective-C interop stubs
Selector references aren't DCEed and thus can cause false positive API usage report from AppStore online validation. Generate selectors by compiler instead.
This commit is contained in:
committed by
SvyatoslavScherbina
parent
0ff1209d0a
commit
f8393819fc
@@ -125,6 +125,10 @@ annotation class InteropStubs()
|
|||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
internal annotation class ObjCMethodImp(val selector: String, val encoding: String)
|
internal annotation class ObjCMethodImp(val selector: String, val encoding: String)
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@TypedIntrinsic(IntrinsicType.OBJC_GET_SELECTOR)
|
||||||
|
internal external fun objCGetSelector(selector: String): COpaquePointer
|
||||||
|
|
||||||
@kotlin.native.internal.ExportForCppRuntime("Kotlin_Interop_getObjCClass")
|
@kotlin.native.internal.ExportForCppRuntime("Kotlin_Interop_getObjCClass")
|
||||||
private fun getObjCClassByName(name: NativePtr): NativePtr {
|
private fun getObjCClassByName(name: NativePtr): NativePtr {
|
||||||
val result = objc_lookUpClass(name)
|
val result = objc_lookUpClass(name)
|
||||||
|
|||||||
+5
-2
@@ -178,6 +178,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
|||||||
|
|
||||||
val kniReceiverParameter = "kniR"
|
val kniReceiverParameter = "kniR"
|
||||||
val kniSuperClassParameter = "kniSC"
|
val kniSuperClassParameter = "kniSC"
|
||||||
|
val kniSelectorParameter = "kniSEL"
|
||||||
|
|
||||||
val voidPtr = PointerType(VoidType)
|
val voidPtr = PointerType(VoidType)
|
||||||
|
|
||||||
@@ -199,6 +200,9 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
|||||||
TypedKotlinValue(voidPtr,
|
TypedKotlinValue(voidPtr,
|
||||||
"getReceiverOrSuper($kniReceiverParameter, $kniSuperClassParameter)"))
|
"getReceiverOrSuper($kniReceiverParameter, $kniSuperClassParameter)"))
|
||||||
|
|
||||||
|
kotlinObjCBridgeParameters.add(KotlinParameter(kniSelectorParameter, KotlinTypes.cOpaquePointer))
|
||||||
|
nativeBridgeArguments.add(TypedKotlinValue(voidPtr, kniSelectorParameter))
|
||||||
|
|
||||||
val kotlinParameterNames = method.getKotlinParameterNames()
|
val kotlinParameterNames = method.getKotlinParameterNames()
|
||||||
|
|
||||||
method.parameters.forEachIndexed { index, it ->
|
method.parameters.forEachIndexed { index, it ->
|
||||||
@@ -224,7 +228,6 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
|||||||
returnType,
|
returnType,
|
||||||
nativeBridgeArguments
|
nativeBridgeArguments
|
||||||
) { nativeValues ->
|
) { nativeValues ->
|
||||||
val selector = "@selector(${method.selector})"
|
|
||||||
val messengerParameterTypes = mutableListOf<String>()
|
val messengerParameterTypes = mutableListOf<String>()
|
||||||
messengerParameterTypes.add("void*")
|
messengerParameterTypes.add("void*")
|
||||||
messengerParameterTypes.add("SEL")
|
messengerParameterTypes.add("SEL")
|
||||||
@@ -239,7 +242,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
|||||||
|
|
||||||
val messenger = "(($messengerType) ${nativeValues.first()})"
|
val messenger = "(($messengerType) ${nativeValues.first()})"
|
||||||
|
|
||||||
val messengerArguments = listOf(nativeValues[1]) + selector + nativeValues.drop(2)
|
val messengerArguments = nativeValues.drop(1)
|
||||||
|
|
||||||
"$messenger(${messengerArguments.joinToString()})"
|
"$messenger(${messengerArguments.joinToString()})"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -233,6 +233,8 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
|
|||||||
val interopCreateNSStringFromKString =
|
val interopCreateNSStringFromKString =
|
||||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.CreateNSStringFromKString)
|
symbolTable.referenceSimpleFunction(context.interopBuiltIns.CreateNSStringFromKString)
|
||||||
|
|
||||||
|
val interopObjCGetSelector = interopFunction("objCGetSelector")
|
||||||
|
|
||||||
val objCExportTrapOnUndeclaredException =
|
val objCExportTrapOnUndeclaredException =
|
||||||
symbolTable.referenceSimpleFunction(context.builtIns.kotlinNativeInternal.getContributedFunctions(
|
symbolTable.referenceSimpleFunction(context.builtIns.kotlinNativeInternal.getContributedFunctions(
|
||||||
Name.identifier("trapOnUndeclaredException"),
|
Name.identifier("trapOnUndeclaredException"),
|
||||||
|
|||||||
+7
@@ -4,6 +4,7 @@ import kotlinx.cinterop.cValuesOf
|
|||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.TypedIntrinsic
|
import org.jetbrains.kotlin.backend.konan.descriptors.TypedIntrinsic
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
|
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.objc.genObjCSelector
|
||||||
import org.jetbrains.kotlin.backend.konan.reportCompilationError
|
import org.jetbrains.kotlin.backend.konan.reportCompilationError
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
@@ -51,6 +52,7 @@ internal enum class IntrinsicType {
|
|||||||
OBJC_GET_OBJC_CLASS,
|
OBJC_GET_OBJC_CLASS,
|
||||||
OBJC_GET_RECEIVER_OR_SUPER,
|
OBJC_GET_RECEIVER_OR_SUPER,
|
||||||
OBJC_INIT_BY,
|
OBJC_INIT_BY,
|
||||||
|
OBJC_GET_SELECTOR,
|
||||||
// Other
|
// Other
|
||||||
GET_CLASS_TYPE_INFO,
|
GET_CLASS_TYPE_INFO,
|
||||||
CREATE_UNINITIALIZED_INSTANCE,
|
CREATE_UNINITIALIZED_INSTANCE,
|
||||||
@@ -148,6 +150,10 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
environment.evaluateCall(constructorDescriptor, args, Lifetime.IRRELEVANT)
|
environment.evaluateCall(constructorDescriptor, args, Lifetime.IRRELEVANT)
|
||||||
receiver
|
receiver
|
||||||
}
|
}
|
||||||
|
IntrinsicType.OBJC_GET_SELECTOR -> {
|
||||||
|
val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String
|
||||||
|
environment.functionGenerationContext.genObjCSelector(selector)
|
||||||
|
}
|
||||||
IntrinsicType.INIT_INSTANCE -> {
|
IntrinsicType.INIT_INSTANCE -> {
|
||||||
val callee = callSite as IrCall
|
val callee = callSite as IrCall
|
||||||
val initializer = callee.getValueArgument(1) as IrCall
|
val initializer = callee.getValueArgument(1) as IrCall
|
||||||
@@ -232,6 +238,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
reportNonLoweredIntrinsic(intrinsicType)
|
reportNonLoweredIntrinsic(intrinsicType)
|
||||||
IntrinsicType.INIT_INSTANCE,
|
IntrinsicType.INIT_INSTANCE,
|
||||||
IntrinsicType.OBJC_INIT_BY,
|
IntrinsicType.OBJC_INIT_BY,
|
||||||
|
IntrinsicType.OBJC_GET_SELECTOR,
|
||||||
IntrinsicType.IMMUTABLE_BLOB ->
|
IntrinsicType.IMMUTABLE_BLOB ->
|
||||||
reportSpecialIntrinsic(intrinsicType)
|
reportSpecialIntrinsic(intrinsicType)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -14,11 +14,7 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
|
|||||||
|
|
||||||
val dataGenerator = codegen.objCDataGenerator!!
|
val dataGenerator = codegen.objCDataGenerator!!
|
||||||
|
|
||||||
fun FunctionGenerationContext.genSelector(selector: String): LLVMValueRef {
|
fun FunctionGenerationContext.genSelector(selector: String): LLVMValueRef = genObjCSelector(selector)
|
||||||
val selectorRef = dataGenerator.genSelectorRef(selector)
|
|
||||||
// TODO: clang emits it with `invariant.load` metadata.
|
|
||||||
return load(selectorRef.llvm)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FunctionGenerationContext.genGetLinkedClass(name: String): LLVMValueRef {
|
fun FunctionGenerationContext.genGetLinkedClass(name: String): LLVMValueRef {
|
||||||
val classRef = dataGenerator.genClassRef(name)
|
val classRef = dataGenerator.genClassRef(name)
|
||||||
@@ -43,3 +39,9 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
|
|||||||
fun msgSender(functionType: LLVMTypeRef): LLVMValueRef =
|
fun msgSender(functionType: LLVMTypeRef): LLVMValueRef =
|
||||||
objcMsgSend.bitcast(pointerType(functionType)).llvm
|
objcMsgSend.bitcast(pointerType(functionType)).llvm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun FunctionGenerationContext.genObjCSelector(selector: String): LLVMValueRef {
|
||||||
|
val selectorRef = codegen.objCDataGenerator!!.genSelectorRef(selector)
|
||||||
|
// TODO: clang emits it with `invariant.load` metadata.
|
||||||
|
return load(selectorRef.llvm)
|
||||||
|
}
|
||||||
+5
-2
@@ -587,10 +587,13 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
|
|||||||
return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
|
return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
|
||||||
putValueArgument(0, superClass)
|
putValueArgument(0, superClass)
|
||||||
putValueArgument(1, receiver)
|
putValueArgument(1, receiver)
|
||||||
|
putValueArgument(2, irCall(symbols.interopObjCGetSelector.owner).apply {
|
||||||
|
putValueArgument(0, irString(info.selector))
|
||||||
|
})
|
||||||
|
|
||||||
assert(arguments.size + 2 == info.bridge.valueParameters.size)
|
assert(arguments.size + 3 == info.bridge.valueParameters.size)
|
||||||
arguments.forEachIndexed { index, argument ->
|
arguments.forEachIndexed { index, argument ->
|
||||||
putValueArgument(index + 2, argument)
|
putValueArgument(index + 3, argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class IntrinsicType {
|
|||||||
const val OBJC_GET_OBJC_CLASS = "OBJC_GET_OBJC_CLASS"
|
const val OBJC_GET_OBJC_CLASS = "OBJC_GET_OBJC_CLASS"
|
||||||
const val OBJC_GET_RECEIVER_OR_SUPER = "OBJC_GET_RECEIVER_OR_SUPER"
|
const val OBJC_GET_RECEIVER_OR_SUPER = "OBJC_GET_RECEIVER_OR_SUPER"
|
||||||
const val OBJC_INIT_BY = "OBJC_INIT_BY"
|
const val OBJC_INIT_BY = "OBJC_INIT_BY"
|
||||||
|
const val OBJC_GET_SELECTOR = "OBJC_GET_SELECTOR"
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
const val GET_CLASS_TYPE_INFO = "GET_CLASS_TYPE_INFO"
|
const val GET_CLASS_TYPE_INFO = "GET_CLASS_TYPE_INFO"
|
||||||
|
|||||||
Reference in New Issue
Block a user