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:
Svyatoslav Scherbina
2019-03-14 15:39:33 +03:00
committed by SvyatoslavScherbina
parent 0ff1209d0a
commit f8393819fc
7 changed files with 31 additions and 9 deletions
@@ -125,6 +125,10 @@ annotation class InteropStubs()
@Retention(AnnotationRetention.SOURCE)
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")
private fun getObjCClassByName(name: NativePtr): NativePtr {
val result = objc_lookUpClass(name)
@@ -178,6 +178,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
val kniReceiverParameter = "kniR"
val kniSuperClassParameter = "kniSC"
val kniSelectorParameter = "kniSEL"
val voidPtr = PointerType(VoidType)
@@ -199,6 +200,9 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
TypedKotlinValue(voidPtr,
"getReceiverOrSuper($kniReceiverParameter, $kniSuperClassParameter)"))
kotlinObjCBridgeParameters.add(KotlinParameter(kniSelectorParameter, KotlinTypes.cOpaquePointer))
nativeBridgeArguments.add(TypedKotlinValue(voidPtr, kniSelectorParameter))
val kotlinParameterNames = method.getKotlinParameterNames()
method.parameters.forEachIndexed { index, it ->
@@ -224,7 +228,6 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
returnType,
nativeBridgeArguments
) { nativeValues ->
val selector = "@selector(${method.selector})"
val messengerParameterTypes = mutableListOf<String>()
messengerParameterTypes.add("void*")
messengerParameterTypes.add("SEL")
@@ -239,7 +242,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
val messenger = "(($messengerType) ${nativeValues.first()})"
val messengerArguments = listOf(nativeValues[1]) + selector + nativeValues.drop(2)
val messengerArguments = nativeValues.drop(1)
"$messenger(${messengerArguments.joinToString()})"
}
@@ -233,6 +233,8 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val interopCreateNSStringFromKString =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.CreateNSStringFromKString)
val interopObjCGetSelector = interopFunction("objCGetSelector")
val objCExportTrapOnUndeclaredException =
symbolTable.referenceSimpleFunction(context.builtIns.kotlinNativeInternal.getContributedFunctions(
Name.identifier("trapOnUndeclaredException"),
@@ -4,6 +4,7 @@ import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.descriptors.TypedIntrinsic
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.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrConstructor
@@ -51,6 +52,7 @@ internal enum class IntrinsicType {
OBJC_GET_OBJC_CLASS,
OBJC_GET_RECEIVER_OR_SUPER,
OBJC_INIT_BY,
OBJC_GET_SELECTOR,
// Other
GET_CLASS_TYPE_INFO,
CREATE_UNINITIALIZED_INSTANCE,
@@ -148,6 +150,10 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
environment.evaluateCall(constructorDescriptor, args, Lifetime.IRRELEVANT)
receiver
}
IntrinsicType.OBJC_GET_SELECTOR -> {
val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String
environment.functionGenerationContext.genObjCSelector(selector)
}
IntrinsicType.INIT_INSTANCE -> {
val callee = callSite as IrCall
val initializer = callee.getValueArgument(1) as IrCall
@@ -232,6 +238,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
reportNonLoweredIntrinsic(intrinsicType)
IntrinsicType.INIT_INSTANCE,
IntrinsicType.OBJC_INIT_BY,
IntrinsicType.OBJC_GET_SELECTOR,
IntrinsicType.IMMUTABLE_BLOB ->
reportSpecialIntrinsic(intrinsicType)
}
@@ -14,11 +14,7 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
val dataGenerator = codegen.objCDataGenerator!!
fun FunctionGenerationContext.genSelector(selector: String): LLVMValueRef {
val selectorRef = dataGenerator.genSelectorRef(selector)
// TODO: clang emits it with `invariant.load` metadata.
return load(selectorRef.llvm)
}
fun FunctionGenerationContext.genSelector(selector: String): LLVMValueRef = genObjCSelector(selector)
fun FunctionGenerationContext.genGetLinkedClass(name: String): LLVMValueRef {
val classRef = dataGenerator.genClassRef(name)
@@ -43,3 +39,9 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
fun msgSender(functionType: LLVMTypeRef): LLVMValueRef =
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)
}
@@ -587,10 +587,13 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
putValueArgument(0, superClass)
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 ->
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_RECEIVER_OR_SUPER = "OBJC_GET_RECEIVER_OR_SUPER"
const val OBJC_INIT_BY = "OBJC_INIT_BY"
const val OBJC_GET_SELECTOR = "OBJC_GET_SELECTOR"
// Other
const val GET_CLASS_TYPE_INFO = "GET_CLASS_TYPE_INFO"