[K/N] refactor all function calls to use LlvmCallable machinery

This commit is contained in:
Pavel Kunyavskiy
2023-02-23 12:28:28 +01:00
committed by Space Team
parent ff3fac5d42
commit 854506fa9e
20 changed files with 417 additions and 437 deletions
@@ -55,7 +55,11 @@ private class CallsChecker(generationState: NativeGenerationState, goodFunctions
listOf(LlvmParamType(llvm.int8PtrType))
)
val checkerFunction = moduleFunction("Kotlin_mm_checkStateAtExternalFunctionCall")
val checkerFunction = llvm.externalNativeRuntimeFunction(
"Kotlin_mm_checkStateAtExternalFunctionCall",
LlvmRetType(llvm.voidType),
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType))
)
private data class ExternalCallInfo(val name: String?, val calledPtr: LLVMValueRef)
@@ -93,7 +97,7 @@ private class CallsChecker(generationState: NativeGenerationState, goodFunctions
val calls = getInstructions(block)
.filter { it.isFunctionCall() }
.toList()
val builder = LLVMCreateBuilderInContext(llvm.llvmContext)
val builder = LLVMCreateBuilderInContext(llvm.llvmContext)!!
for (call in calls) {
val calleeInfo = call.getPossiblyExternalCalledFunction() ?: continue
@@ -102,21 +106,21 @@ private class CallsChecker(generationState: NativeGenerationState, goodFunctions
LLVMBuilderResetDebugLocation(builder)
val callSiteDescription: String
val calledName: String?
val calledPtrLlvm: LLVMValueRef?
val calledPtrLlvm: LLVMValueRef
when (calleeInfo.name) {
"objc_msgSend" -> {
// objc_msgSend has wrong declaration in header, so generated wrapper is strange, Let's just skip it
if (LLVMGetNumArgOperands(call) < 2) continue
callSiteDescription = "$functionName (over objc_msgSend)"
calledName = null
val firstArgI8Ptr = LLVMBuildBitCast(builder, LLVMGetArgOperand(call, 0), llvm.int8PtrType, "")
val firstArgClassPtr = LLVMBuildCall(builder, getClass.llvmValue, listOf(firstArgI8Ptr).toCValues(), 1, "")
val firstArgI8Ptr = LLVMBuildBitCast(builder, LLVMGetArgOperand(call, 0), llvm.int8PtrType, "")!!
val firstArgClassPtr = getClass.buildCall(builder, listOf(firstArgI8Ptr))
val isNil = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, firstArgI8Ptr, LLVMConstNull(llvm.int8PtrType), "")
val selector = LLVMGetArgOperand(call, 1)
val calledPtrLlvmIfNotNilFunPtr = LLVMBuildCall(builder, getMethodImpl.llvmValue, listOf(firstArgClassPtr, selector).toCValues(), 2, "")
val selector = LLVMGetArgOperand(call, 1)!!
val calledPtrLlvmIfNotNilFunPtr = getMethodImpl.buildCall(builder, listOf(firstArgClassPtr, selector))
val calledPtrLlvmIfNotNil = LLVMBuildBitCast(builder, calledPtrLlvmIfNotNilFunPtr, llvm.int8PtrType, "")
val calledPtrLlvmIfNil = LLVMConstIntToPtr(llvm.int64(MSG_SEND_TO_NULL), llvm.int8PtrType)
calledPtrLlvm = LLVMBuildSelect(builder, isNil, calledPtrLlvmIfNil, calledPtrLlvmIfNotNil, "")
calledPtrLlvm = LLVMBuildSelect(builder, isNil, calledPtrLlvmIfNil, calledPtrLlvmIfNotNil, "")!!
}
"objc_msgSendSuper2" -> {
if (LLVMGetNumArgOperands(call) < 2) continue
@@ -124,30 +128,30 @@ private class CallsChecker(generationState: NativeGenerationState, goodFunctions
calledName = null
val superStruct = LLVMGetArgOperand(call, 0)
val superClassPtrPtr = LLVMBuildGEP(builder, superStruct, listOf(llvm.int32(0), llvm.int32(1)).toCValues(), 2, "")
val superClassPtr = LLVMBuildLoad(builder, superClassPtrPtr, "")
val classPtr = LLVMBuildCall(builder, getSuperClass.llvmValue, listOf(superClassPtr).toCValues(), 1, "")
val calledPtrLlvmFunPtr = LLVMBuildCall(builder, getMethodImpl.llvmValue, listOf(classPtr, LLVMGetArgOperand(call, 1)).toCValues(), 2, "")
calledPtrLlvm = LLVMBuildBitCast(builder, calledPtrLlvmFunPtr, llvm.int8PtrType, "")
val superClassPtr = LLVMBuildLoad(builder, superClassPtrPtr, "")!!
val classPtr = getSuperClass.buildCall(builder, listOf(superClassPtr))
val calledPtrLlvmFunPtr = getMethodImpl.buildCall(builder, listOf(classPtr, LLVMGetArgOperand(call, 1)!!))
calledPtrLlvm = LLVMBuildBitCast(builder, calledPtrLlvmFunPtr, llvm.int8PtrType, "")!!
}
else -> {
callSiteDescription = functionName
calledName = calleeInfo.name
calledPtrLlvm = when (val typeKind = LLVMGetTypeKind(calleeInfo.calledPtr.type)) {
LLVMTypeKind.LLVMPointerTypeKind -> LLVMBuildBitCast(builder, calleeInfo.calledPtr, llvm.int8PtrType, "")
LLVMTypeKind.LLVMIntegerTypeKind -> LLVMBuildIntToPtr(builder, calleeInfo.calledPtr, llvm.int8PtrType, "")
LLVMTypeKind.LLVMPointerTypeKind -> LLVMBuildBitCast(builder, calleeInfo.calledPtr, llvm.int8PtrType, "")!!
LLVMTypeKind.LLVMIntegerTypeKind -> LLVMBuildIntToPtr(builder, calleeInfo.calledPtr, llvm.int8PtrType, "")!!
else -> TODO("Unsupported typeKind=${typeKind} of calledPtr=${llvm2string(calleeInfo.calledPtr)}")
}
}
}
val callSiteDescriptionLlvm = llvm.staticData.cStringLiteral(callSiteDescription).llvm
val calledNameLlvm = if (calledName == null) LLVMConstNull(llvm.int8PtrType) else llvm.staticData.cStringLiteral(calledName).llvm
LLVMBuildCall(builder, checkerFunction, listOf(callSiteDescriptionLlvm, calledNameLlvm, calledPtrLlvm).toCValues(), 3, "")
val calledNameLlvm = if (calledName == null) LLVMConstNull(llvm.int8PtrType)!! else llvm.staticData.cStringLiteral(calledName).llvm
checkerFunction.buildCall(builder, listOf(callSiteDescriptionLlvm, calledNameLlvm, calledPtrLlvm))
}
LLVMDisposeBuilder(builder)
}
fun processFunction(function: LLVMValueRef) {
if (function == checkerFunction) return
if (function.name == checkerFunction.name) return
getBasicBlocks(function).forEach {
processBasicBlock(function.name!!, it)
}
@@ -180,8 +184,8 @@ internal fun checkLlvmModuleExternalCalls(generationState: NativeGenerationState
.filter { !it.isExternalFunction() && it !in ignoredFunctions }
.forEach(checker::processFunction)
// otherwise optimiser can inline it
staticData.getGlobal(functionListGlobal)?.setExternallyInitialized(true);
staticData.getGlobal(functionListSizeGlobal)?.setExternallyInitialized(true);
staticData.getGlobal(functionListGlobal)?.setExternallyInitialized(true)
staticData.getGlobal(functionListSizeGlobal)?.setExternallyInitialized(true)
verifyModule(llvm.module)
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.backend.konan.cexport
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.llvm.*
@@ -13,8 +12,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.CodeGenerator
import org.jetbrains.kotlin.backend.konan.llvm.ContextUtils
import org.jetbrains.kotlin.backend.konan.llvm.ExceptionHandler
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.backend.konan.llvm.addLlvmFunctionWithDefaultAttributes
import org.jetbrains.kotlin.backend.konan.llvm.generateFunction
import org.jetbrains.kotlin.backend.konan.lower.getObjectClassInstanceFunction
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -48,9 +45,10 @@ internal class CAdapterCodegen(
val function = declaration as FunctionDescriptor
val irFunction = irSymbol.owner as IrFunction
cname = "_konan_function_${owner.nextFunctionIndex()}"
val llvmCallable = codegen.llvmFunction(irFunction)
val signature = LlvmFunctionSignature(irFunction, this@CAdapterCodegen)
val bridgeFunctionProto = signature.toProto(cname, null, LLVMLinkage.LLVMExternalLinkage)
// If function is virtual, we need to resolve receiver properly.
val bridge = generateFunction(codegen, llvmCallable.functionType, cname) {
generateFunction(codegen, bridgeFunctionProto) {
val callee = if (!DescriptorUtils.isTopLevelDeclaration(function) &&
irFunction.isOverridable
) {
@@ -59,35 +57,36 @@ internal class CAdapterCodegen(
} else {
// KT-45468: Alias insertion may not be handled by LLVM properly, in case callee is in the cache.
// Hence, insert not an alias but a wrapper, hoping it will be optimized out later.
llvmCallable
codegen.llvmFunction(irFunction)
}
val numParams = LLVMCountParams(llvmCallable.llvmValue)
val args = (0 until numParams).map { index -> param(index) }
callee.attributeProvider.addFunctionAttributes(this.function)
val args = signature.parameterTypes.indices.map { param(it) }
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
ret(result)
}
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
}
isClass -> {
val irClass = irSymbol.owner as IrClass
cname = "_konan_function_${owner.nextFunctionIndex()}"
// Produce type getter.
val getTypeFunction = addLlvmFunctionWithDefaultAttributes(
context,
llvm.module,
"${cname}_type",
kGetTypeFuncType
)
val getTypeFunction = kGetTypeFuncType.toProto(
"${cname}_type",
null,
LLVMLinkage.LLVMExternalLinkage
).createLlvmFunction(context, llvm.module)
val builder = LLVMCreateBuilderInContext(llvm.llvmContext)!!
val bb = LLVMAppendBasicBlockInContext(llvm.llvmContext, getTypeFunction, "")!!
val bb = getTypeFunction.addBasicBlock(llvm.llvmContext)
LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, irClass.typeInfoPtr.llvm)
LLVMDisposeBuilder(builder)
// Produce instance getter if needed.
if (isSingletonObject) {
generateFunction(codegen, kGetObjectFuncType, "${cname}_instance") {
val functionProto = kGetObjectFuncType.toProto(
"${cname}_instance",
null,
LLVMLinkage.LLVMExternalLinkage
)
generateFunction(codegen, functionProto) {
val value = call(
codegen.llvmFunction(context.getObjectClassInstanceFunction(irClass)),
emptyList(),
@@ -103,7 +102,12 @@ internal class CAdapterCodegen(
isEnumEntry -> {
// Produce entry getter.
cname = "_konan_function_${owner.nextFunctionIndex()}"
generateFunction(codegen, kGetObjectFuncType, cname) {
val functionProto = kGetObjectFuncType.toProto(
cname,
null,
LLVMLinkage.LLVMExternalLinkage
)
generateFunction(codegen, functionProto) {
val irEnumEntry = irSymbol.owner as IrEnumEntry
val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller)
ret(value)
@@ -112,8 +116,8 @@ internal class CAdapterCodegen(
}
}
private val kGetTypeFuncType = LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!!
private val kGetTypeFuncType = LlvmFunctionSignature(LlvmRetType(codegen.kTypeInfoPtr))
// Abstraction leak for slot :(.
private val kGetObjectFuncType = LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!!
private val kGetObjectFuncType = LlvmFunctionSignature(LlvmRetType(codegen.kObjHeaderPtr), listOf(LlvmParamType(codegen.kObjHeaderPtrPtr)))
}
@@ -24,6 +24,9 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind
internal class CodeGenerator(override val generationState: NativeGenerationState) : ContextUtils {
fun addFunction(proto: LlvmFunctionProto): LlvmCallable =
proto.createLlvmFunction(context, llvm.module)
fun llvmFunction(function: IrFunction): LlvmCallable =
llvmFunctionOrNull(function)
?: error("no function ${function.name} in ${function.file.fqName}")
@@ -42,12 +45,7 @@ internal class CodeGenerator(override val generationState: NativeGenerationState
fun typeInfoValue(irClass: IrClass): LLVMValueRef = irClass.llvmTypeInfoPtr
fun param(fn: IrFunction, i: Int): LLVMValueRef {
assert(i >= 0 && i < countParams(fn))
return LLVMGetParam(fn.llvmFunction.llvmValue, i)!!
}
private fun countParams(fn: IrFunction) = LLVMCountParams(fn.llvmFunction.llvmValue)
fun param(fn: IrFunction, i: Int) = fn.llvmFunction.param(i)
fun functionEntryPointAddress(function: IrFunction) = function.entryPointAddress.llvm
@@ -108,7 +106,7 @@ internal inline fun generateFunction(
endLocation: LocationInfo?,
code: FunctionGenerationContext.() -> Unit
) {
val llvmFunction = codegen.llvmFunction(function).llvmValue
val llvmFunction = codegen.llvmFunction(function)
val isCToKotlinBridge = function.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE
@@ -131,13 +129,9 @@ internal inline fun generateFunction(
} finally {
functionGenerationContext.dispose()
}
// To perform per-function validation.
if (false)
LLVMVerifyFunction(llvmFunction, LLVMVerifierFailureAction.LLVMAbortProcessAction)
}
internal inline fun <T : FunctionGenerationContext> FunctionGenerationContextBuilder<T>.generate(code: T.() -> Unit): LLVMValueRef {
internal inline fun <T : FunctionGenerationContext> FunctionGenerationContextBuilder<T>.generate(code: T.() -> Unit): LlvmCallable {
val functionGenerationContext = this.build()
return try {
generateFunctionBody(functionGenerationContext, code)
@@ -149,12 +143,13 @@ internal inline fun <T : FunctionGenerationContext> FunctionGenerationContextBui
internal inline fun generateFunction(
codegen: CodeGenerator,
function: LLVMValueRef,
functionProto: LlvmFunctionProto,
startLocation: LocationInfo? = null,
endLocation: LocationInfo? = null,
switchToRunnable: Boolean = false,
code: FunctionGenerationContext.() -> Unit
) {
) : LlvmCallable {
val function = codegen.addFunction(functionProto)
val functionGenerationContext = DefaultFunctionGenerationContext(
function,
codegen,
@@ -167,31 +162,16 @@ internal inline fun generateFunction(
} finally {
functionGenerationContext.dispose()
}
}
internal inline fun generateFunction(
codegen: CodeGenerator,
functionType: LLVMTypeRef,
name: String,
switchToRunnable: Boolean = false,
block: FunctionGenerationContext.() -> Unit
): LLVMValueRef {
val function = addLlvmFunctionWithDefaultAttributes(
codegen.context,
codegen.llvm.module,
name,
functionType
)
generateFunction(codegen, function, startLocation = null, endLocation = null, switchToRunnable = switchToRunnable, code = block)
return function
}
// TODO: Consider using different abstraction than `FunctionGenerationContext` for `generateFunctionNoRuntime`.
internal inline fun generateFunctionNoRuntime(
codegen: CodeGenerator,
function: LLVMValueRef,
functionProto: LlvmFunctionProto,
code: FunctionGenerationContext.() -> Unit,
) {
) : LlvmCallable {
val function = codegen.addFunction(functionProto)
val functionGenerationContext = DefaultFunctionGenerationContext(function, codegen, null, null, switchToRunnable = false)
try {
functionGenerationContext.forbidRuntime = true
@@ -203,21 +183,6 @@ internal inline fun generateFunctionNoRuntime(
} finally {
functionGenerationContext.dispose()
}
}
internal inline fun generateFunctionNoRuntime(
codegen: CodeGenerator,
functionType: LLVMTypeRef,
name: String,
code: FunctionGenerationContext.() -> Unit,
): LLVMValueRef {
val function = addLlvmFunctionWithDefaultAttributes(
codegen.context,
codegen.llvm.module,
name,
functionType
)
generateFunctionNoRuntime(codegen, function, code)
return function
}
@@ -413,17 +378,12 @@ internal class StackLocalsManagerImpl(
}
internal abstract class FunctionGenerationContextBuilder<T : FunctionGenerationContext>(
val function: LLVMValueRef,
val function: LlvmCallable,
val codegen: CodeGenerator
) {
constructor(functionType: LLVMTypeRef, functionName: String, codegen: CodeGenerator) :
constructor(functionProto: LlvmFunctionProto, codegen: CodeGenerator) :
this(
addLlvmFunctionWithDefaultAttributes(
codegen.context,
codegen.llvm.module,
functionName,
functionType
),
codegen.addFunction(functionProto),
codegen
)
@@ -436,7 +396,7 @@ internal abstract class FunctionGenerationContextBuilder<T : FunctionGenerationC
}
internal abstract class FunctionGenerationContext(
val function: LLVMValueRef,
val function: LlvmCallable,
val codegen: CodeGenerator,
private val startLocation: LocationInfo?,
protected val endLocation: LocationInfo?,
@@ -463,7 +423,7 @@ internal abstract class FunctionGenerationContext(
basicBlockToLastLocation.put(block, LocationInfoRange(startLocationInfo, endLocation))
}
var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function))
var returnType: LLVMTypeRef? = function.returnType
val constructedClass: IrClass?
get() = (irFunction as? IrConstructor)?.constructedClass
var returnSlot: LLVMValueRef? = null
@@ -499,11 +459,9 @@ internal abstract class FunctionGenerationContext(
data class FunctionInvokeInformation(
val invokeInstruction: LLVMValueRef,
val llvmFunction: LLVMValueRef,
val rargs: CValues<CPointerVar<LLVMOpaqueValue>>,
val argsNumber: Int,
val llvmFunction: LlvmCallable,
val args: List<LLVMValueRef>,
val success: LLVMBasicBlockRef,
val attributeProvider: LlvmFunctionAttributeProvider?
)
private val invokeInstructions = mutableListOf<FunctionInvokeInformation>()
@@ -519,21 +477,12 @@ internal abstract class FunctionGenerationContext(
// TODO: Consider using a different abstraction than `FunctionGenerationContext`.
var forbidRuntime = false
init {
irFunction?.let {
if (!irFunction.isExported()) {
if (!context.config.producePerFileCache || irFunction !in generationState.calledFromExportedInlineFunctions)
LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage) // (Cannot do this before the function body is created)
}
}
}
fun dispose() {
currentPositionHolder.dispose()
}
protected fun basicBlockInFunction(name: String, locationInfo: LocationInfo?): LLVMBasicBlockRef {
val bb = LLVMAppendBasicBlockInContext(llvm.llvmContext, function, name)!!
val bb = function.addBasicBlock(llvm.llvmContext, name)
update(bb, locationInfo)
return bb
}
@@ -585,7 +534,7 @@ internal abstract class FunctionGenerationContext(
abstract fun ret(value: LLVMValueRef?): LLVMValueRef
fun param(index: Int): LLVMValueRef = LLVMGetParam(this.function, index)!!
fun param(index: Int): LLVMValueRef = function.param(index)
fun load(address: LLVMValueRef, name: String = "",
memoryOrder: LLVMAtomicOrdering? = null, alignment: Int? = null
@@ -699,17 +648,8 @@ internal abstract class FunctionGenerationContext(
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
verbatim: Boolean = false,
resultSlot: LLVMValueRef? = null,
): LLVMValueRef =
call(llvmCallable.llvmValue, args, resultLifetime, exceptionHandler, verbatim, llvmCallable.attributeProvider, resultSlot)
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
verbatim: Boolean = false,
attributeProvider: LlvmFunctionAttributeProvider? = null,
resultSlot: LLVMValueRef? = null
): LLVMValueRef {
val callArgs = if (verbatim || !isObjectReturn(llvmFunction.type)) {
val callArgs = if (verbatim || !isObjectType(llvmCallable.returnType)) {
args
} else {
// If function returns an object - create slot for the returned value or give local arena.
@@ -719,7 +659,7 @@ internal abstract class FunctionGenerationContext(
SlotType.STACK -> {
localAllocs++
// Case of local call. Use memory allocated on stack.
val type = LLVMGetReturnType(LLVMGetElementType(llvmFunction.type))!!
val type = llvmCallable.returnType
val stackPointer = alloca(type)
//val objectHeader = structGep(stackPointer, 0)
//setTypeInfoForLocalObject(objectHeader)
@@ -735,18 +675,13 @@ internal abstract class FunctionGenerationContext(
}
args + realResultSlot
}
return callRaw(llvmFunction, callArgs, exceptionHandler, attributeProvider)
return callRaw(llvmCallable, callArgs, exceptionHandler)
}
private fun callRaw(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
exceptionHandler: ExceptionHandler,
attributeProvider: LlvmFunctionAttributeProvider?): LLVMValueRef {
val rargs = args.toCValues()
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
isFunctionNoUnwind(llvmFunction)) {
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!.also {
attributeProvider?.addCallSiteAttributes(it)
}
private fun callRaw(llvmCallable: LlvmCallable, args: List<LLVMValueRef>,
exceptionHandler: ExceptionHandler): LLVMValueRef {
if (llvmCallable.isNoUnwind) {
return llvmCallable.buildCall(builder, args)
} else {
val unwind = when (exceptionHandler) {
ExceptionHandler.Caller -> cleanupLandingpad
@@ -756,7 +691,7 @@ internal abstract class FunctionGenerationContext(
// When calling a function that is not marked as nounwind (can throw an exception),
// it is required to specify an unwind label to handle exceptions properly.
// Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`.
val functionName = llvmFunction.name
val functionName = llvmCallable.name
val message =
"no exception handler specified when calling function $functionName without nounwind attr"
throw IllegalArgumentException(message)
@@ -766,13 +701,12 @@ internal abstract class FunctionGenerationContext(
val position = position()
val endLocation = position?.end
val success = basicBlock("call_success", endLocation)
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!!
attributeProvider?.addCallSiteAttributes(result)
val result = llvmCallable.buildInvoke(builder, args, success, unwind)
// Store invoke instruction and its success block in reverse order.
// Reverse order allows save arguments valid during all work with invokes
// because other invokes processed before can be inside arguments list.
if (exceptionHandler == ExceptionHandler.Caller)
invokeInstructions.add(0, FunctionInvokeInformation(result, llvmFunction, rargs, args.size, success, attributeProvider))
invokeInstructions.add(0, FunctionInvokeInformation(result, llvmCallable, args, success))
positionAtEnd(success)
return result
@@ -846,7 +780,7 @@ internal abstract class FunctionGenerationContext(
}
fun blockAddress(bbLabel: LLVMBasicBlockRef): LLVMValueRef {
return LLVMBlockAddress(function, bbLabel)!!
return function.blockAddress(bbLabel)
}
fun not(arg: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildNot(builder, arg, name)!!
@@ -927,12 +861,11 @@ internal abstract class FunctionGenerationContext(
LLVMBuildExtractValue(builder, aggregate, index, name)!!
fun gxxLandingpad(numClauses: Int, name: String = "", switchThreadState: Boolean = false): LLVMValueRef {
val personalityFunction = llvm.gxxPersonalityFunction.llvmValue
val personalityFunction = llvm.gxxPersonalityFunction
// Type of `landingpad` instruction result (depends on personality function):
val landingpadType = llvm.structType(llvm.int8PtrType, llvm.int32Type)
val landingpad = LLVMBuildLandingPad(builder, landingpadType, personalityFunction, numClauses, name)!!
val landingpad = personalityFunction.buildLandingpad(builder, landingpadType, numClauses, name)
if (switchThreadState) {
switchThreadState(Runnable)
@@ -1286,7 +1219,7 @@ internal abstract class FunctionGenerationContext(
val enumClass = enumEntry.parentAsClass
val getterId = context.enumsSupport.enumEntriesMap(enumClass)[enumEntry.name]!!.getterId
return call(
context.enumsSupport.getValueGetter(enumClass).llvmFunction.llvmValue,
context.enumsSupport.getValueGetter(enumClass).llvmFunction,
listOf(llvm.int32(getterId)),
Lifetime.GLOBAL,
exceptionHandler
@@ -1356,7 +1289,7 @@ internal abstract class FunctionGenerationContext(
internal fun prologue() {
if (isObjectType(returnType!!)) {
returnSlot = LLVMGetParam(function, numParameters(function.type) - 1)
returnSlot = function.param( function.numParams - 1)
}
positionAtEnd(localsInitBb)
@@ -1449,9 +1382,7 @@ internal abstract class FunctionGenerationContext(
// Replace invokes with calls and branches.
invokeInstructions.forEach { functionInvokeInfo ->
positionBefore(functionInvokeInfo.invokeInstruction)
val newResult = LLVMBuildCall(builder, functionInvokeInfo.llvmFunction, functionInvokeInfo.rargs,
functionInvokeInfo.argsNumber, "")!!
functionInvokeInfo.attributeProvider?.addCallSiteAttributes(newResult)
val newResult = functionInvokeInfo.llvmFunction.buildCall(builder, functionInvokeInfo.args)
// Have to generate `br` instruction because of current scheme of debug info.
br(functionInvokeInfo.success)
LLVMReplaceAllUsesWith(functionInvokeInfo.invokeInstruction, newResult)
@@ -1636,7 +1567,7 @@ internal abstract class FunctionGenerationContext(
}
internal class DefaultFunctionGenerationContext(
function: LLVMValueRef,
function: LlvmCallable,
codegen: CodeGenerator,
startLocation: LocationInfo?,
endLocation: LocationInfo?,
@@ -184,7 +184,7 @@ internal interface ContextUtils : RuntimeAware {
?: context.irLinker.getExternalDeclarationFileName(this)
this.computePrivateSymbolName(containerName)
}
val proto = LlvmFunctionProto(this, symbolName, this@ContextUtils)
val proto = LlvmFunctionProto(this, symbolName, this@ContextUtils, LLVMLinkage.LLVMExternalLinkage)
llvm.externalFunction(proto)
}
} else {
@@ -197,8 +197,7 @@ internal interface ContextUtils : RuntimeAware {
*/
val IrFunction.entryPointAddress: ConstPointer
get() {
val result = LLVMConstBitCast(this.llvmFunction.llvmValue, llvm.int8PtrType)!!
return constPointer(result)
return llvmFunction.toConstPointer().bitcast(llvm.int8PtrType)
}
val IrClass.typeInfoPtr: ConstPointer
@@ -356,19 +355,19 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
}
internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable {
this.dependenciesTracker.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent)
if (llvmFunctionProto.origin != null) {
this.dependenciesTracker.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent)
}
val found = LLVMGetNamedFunction(module, llvmFunctionProto.name)
if (found != null) {
assert(getFunctionType(found) == llvmFunctionProto.llvmFunctionType) {
"Expected: ${LLVMPrintTypeToString(llvmFunctionProto.llvmFunctionType)!!.toKString()} " +
require(getFunctionType(found) == llvmFunctionProto.signature.llvmFunctionType) {
"Expected: ${LLVMPrintTypeToString(llvmFunctionProto.signature.llvmFunctionType)!!.toKString()} " +
"found: ${LLVMPrintTypeToString(getFunctionType(found))!!.toKString()}"
}
assert(LLVMGetLinkage(found) == LLVMLinkage.LLVMExternalLinkage)
return LlvmCallable(found, llvmFunctionProto)
require(LLVMGetLinkage(found) == llvmFunctionProto.linkage)
return LlvmCallable(found, llvmFunctionProto.signature)
} else {
val function = addLlvmFunctionWithDefaultAttributes(context, module, llvmFunctionProto.name, llvmFunctionProto.llvmFunctionType)
llvmFunctionProto.addFunctionAttributes(function)
return LlvmCallable(function, llvmFunctionProto)
return llvmFunctionProto.createLlvmFunction(context, module)
}
}
@@ -379,9 +378,12 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
isVararg: Boolean = false
) = externalFunction(
LlvmFunctionProto(name, returnType, parameterTypes, functionAttributes,
LlvmFunctionSignature(returnType, parameterTypes, isVararg, functionAttributes).toProto(
name,
origin = FunctionOrigin.FromNativeRuntime,
isVararg, independent = false)
linkage = LLVMLinkage.LLVMExternalLinkage,
independent = false
)
)
internal fun externalNativeRuntimeFunction(name: String, signature: LlvmFunctionSignature) =
@@ -479,7 +481,6 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
val CompareAndSwapVolatileHeapRef by lazyRtFunction
val GetAndSetVolatileHeapRef by lazyRtFunction
val tlsMode by lazy {
when (target) {
KonanTarget.WASM32,
@@ -488,12 +489,11 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
}
}
val usedFunctions = mutableListOf<LLVMValueRef>()
val usedFunctions = mutableListOf<LlvmCallable>()
val usedGlobals = mutableListOf<LLVMValueRef>()
val compilerUsedGlobals = mutableListOf<LLVMValueRef>()
val irStaticInitializers = mutableListOf<IrStaticInitializer>()
val otherStaticInitializers = mutableListOf<LLVMValueRef>()
val globalSharedObjects = mutableSetOf<LLVMValueRef>()
val otherStaticInitializers = mutableListOf<LlvmCallable>()
val initializersGenerationState = InitializersGenerationState()
val boxCacheGlobals = mutableMapOf<BoxCache, StaticData.Global>()
@@ -605,25 +605,23 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind)
)
private fun getSizeOfReturnTypeInBits(functionPointer: LLVMValueRef): Long {
// LLVMGetElementType is called because we need to dereference a pointer to function.
val nsIntegerType = LLVMGetReturnType(LLVMGetElementType(functionPointer.type))
return LLVMSizeOfTypeInBits(runtime.targetData, nsIntegerType)
private fun getSizeOfTypeInBits(type: LLVMTypeRef): Long {
return LLVMSizeOfTypeInBits(runtime.targetData, type)
}
/**
* Width of NSInteger in bits.
*/
val nsIntegerTypeWidth: Long by lazy {
getSizeOfReturnTypeInBits(Kotlin_ObjCExport_NSIntegerTypeProvider.llvmValue)
getSizeOfTypeInBits(Kotlin_ObjCExport_NSIntegerTypeProvider.returnType)
}
/**
* Width of C long type in bits.
*/
val longTypeWidth: Long by lazy {
getSizeOfReturnTypeInBits(Kotlin_longTypeProvider.llvmValue)
getSizeOfTypeInBits(Kotlin_longTypeProvider.returnType)
}
}
class IrStaticInitializer(val konanLibrary: KotlinLibrary?, val initializer: LLVMValueRef)
class IrStaticInitializer(val konanLibrary: KotlinLibrary?, val initializer: LlvmCallable)
@@ -132,7 +132,7 @@ internal class DebugInfo(override val generationState: NativeGenerationState) :
}
val files = mutableMapOf<String, DIFileRef>()
val subprograms = mutableMapOf<LLVMValueRef, DISubprogramRef>()
val subprograms = mutableMapOf<LlvmCallable, DISubprogramRef>()
/* Some functions are inlined on all callsites and body is eliminated by DCE, so there's no LLVM value */
val inlinedSubprograms = mutableMapOf<IrFunction, DISubprogramRef>()
@@ -264,7 +264,7 @@ internal fun String?.toFileAndFolder(config: KonanConfig): FileAndFolder {
internal fun alignTo(value: Long, align: Long): Long = (value + align - 1) / align * align
internal fun setupBridgeDebugInfo(generationState: NativeGenerationState, function: LLVMValueRef): LocationInfo? {
internal fun setupBridgeDebugInfo(generationState: NativeGenerationState, function: LlvmCallable): LocationInfo? {
if (!generationState.shouldContainLocationDebugInfo()) {
return null
}
@@ -273,17 +273,16 @@ internal fun setupBridgeDebugInfo(generationState: NativeGenerationState, functi
val file = debugInfo.compilerGeneratedFile
// TODO: can we share the scope among all bridges?
val scope: DIScopeOpaqueRef = DICreateBridgeFunction(
val scope: DIScopeOpaqueRef = function.createBridgeFunctionDebugInfo(
builder = debugInfo.builder,
scope = file.reinterpret(),
function = function,
file = file,
lineNo = 0,
type = debugInfo.subroutineType(generationState.runtime.targetData, emptyList()), // TODO: use proper type.
isLocal = 0,
isDefinition = 1,
scopeLine = 0
)!!.reinterpret()
).reinterpret()
return LocationInfo(scope, 1, 0)
}
@@ -559,8 +559,8 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
val superClass = args.single()
val messenger = LLVMBuildSelect(builder,
If = icmpEq(superClass, llvm.kNullInt8Ptr),
Then = normalMessenger.llvmValue,
Else = superMessenger.llvmValue,
Then = normalMessenger.toConstPointer().llvm,
Else = superMessenger.toConstPointer().llvm,
Name = ""
)!!
@@ -84,6 +84,14 @@ internal fun IrField.isGlobalNonPrimitive(context: Context) = when {
internal fun IrField.shouldBeFrozen(context: Context): Boolean =
this.storageKind(context) == FieldStorageKind.SHARED_FROZEN
internal fun IrFunction.shouldGenerateBody(): Boolean = when {
this is IrConstructor && constructedClass.isInlined() -> false
this is IrConstructor && isObjCConstructor -> false
this is IrSimpleFunction && modality == Modality.ABSTRACT -> false
isExternal -> false
else -> true
}
internal class RTTIGeneratorVisitor(generationState: NativeGenerationState, referencedFunctions: Set<IrFunction>?) : IrElementVisitorVoid {
val generator = RTTIGenerator(generationState, referencedFunctions)
@@ -441,7 +449,7 @@ internal class CodeGeneratorVisitor(
generationState.coverage.writeRegionInfo()
overrideRuntimeGlobals()
appendLlvmUsed("llvm.used", llvm.usedFunctions + llvm.usedGlobals)
appendLlvmUsed("llvm.used", llvm.usedFunctions.map { it.toConstPointer().llvm } + llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", llvm.compilerUsedGlobals)
if (context.config.produce.isNativeLibrary) {
context.cAdapterExportedElements?.let { appendCAdapters(it) }
@@ -453,10 +461,10 @@ internal class CodeGeneratorVisitor(
//-------------------------------------------------------------------------//
val kVoidFuncType = functionType(llvm.voidType)
val ctorFunctionSignature = LlvmFunctionSignature(LlvmRetType(llvm.voidType))
val kNodeInitType = LLVMGetTypeByName(llvm.module, "struct.InitNode")!!
val kMemoryStateType = LLVMGetTypeByName(llvm.module, "struct.MemoryState")!!
val kInitFuncType = functionType(llvm.voidType, false, llvm.int32Type, pointerType(kMemoryStateType))
val kInitFuncType = LlvmFunctionSignature(LlvmRetType(llvm.voidType), listOf(LlvmParamType(llvm.int32Type), LlvmParamType(pointerType(kMemoryStateType))))
//-------------------------------------------------------------------------//
@@ -469,16 +477,10 @@ internal class CodeGeneratorVisitor(
val FILE_NOT_INITIALIZED = 0
val FILE_INITIALIZED = 2
private fun createInitBody(state: ScopeInitializersGenerationState): LLVMValueRef {
val initFunction = addLlvmFunctionWithDefaultAttributes(
generationState.context,
llvm.module,
"",
kInitFuncType
)
LLVMSetLinkage(initFunction, LLVMLinkage.LLVMPrivateLinkage)
generateFunction(codegen, initFunction) {
using(FunctionScope(initFunction, this)) {
private fun createInitBody(state: ScopeInitializersGenerationState): LlvmCallable {
val initFunctionProto = kInitFuncType.toProto("", null, LLVMLinkage.LLVMPrivateLinkage)
return generateFunction(codegen, initFunctionProto) {
using(FunctionScope(function, this)) {
val bbInit = basicBlock("init", null)
val bbLocalInit = basicBlock("local_init", null)
val bbLocalAlloc = basicBlock("local_alloc", null)
@@ -487,7 +489,7 @@ internal class CodeGeneratorVisitor(
unreachable()
}
switch(LLVMGetParam(initFunction, 0)!!,
switch(function.param(0),
listOf(llvm.int32(INIT_GLOBALS) to bbInit,
llvm.int32(INIT_THREAD_LOCAL_GLOBALS) to bbLocalInit,
llvm.int32(ALLOC_THREAD_LOCAL_GLOBALS) to bbLocalAlloc,
@@ -513,7 +515,7 @@ internal class CodeGeneratorVisitor(
appendingTo(bbLocalAlloc) {
if (llvm.tlsCount > 0) {
val memory = LLVMGetParam(initFunction, 1)!!
val memory = function.param(1)
call(llvm.addTLSRecord, listOf(memory, llvm.tlsKey, llvm.int32(llvm.tlsCount)))
}
ret(null)
@@ -538,15 +540,14 @@ internal class CodeGeneratorVisitor(
}
}
}
return initFunction
}
//-------------------------------------------------------------------------//
// Creates static struct InitNode $nodeName = {$initName, NULL};
private fun createInitNode(initFunction: LLVMValueRef): LLVMValueRef {
private fun createInitNode(initFunction: LlvmCallable): LLVMValueRef {
val nextInitNode = LLVMConstNull(pointerType(kNodeInitType))
val argList = cValuesOf(initFunction, nextInitNode)
val argList = cValuesOf(initFunction.toConstPointer().llvm, nextInitNode)
// Create static object of class InitNode.
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!!
// Create global variable with init record data.
@@ -555,13 +556,13 @@ internal class CodeGeneratorVisitor(
//-------------------------------------------------------------------------//
private fun createInitCtor(initNodePtr: LLVMValueRef): LLVMValueRef {
val ctorFunction = generateFunctionNoRuntime(codegen, kVoidFuncType, "") {
private fun createInitCtor(initNodePtr: LLVMValueRef): LlvmCallable {
val ctorProto = ctorFunctionSignature.toProto("", null, LLVMLinkage.LLVMPrivateLinkage)
val ctor = generateFunctionNoRuntime(codegen, ctorProto) {
call(llvm.appendToInitalizersTail, listOf(initNodePtr))
ret(null)
}
LLVMSetLinkage(ctorFunction, LLVMLinkage.LLVMPrivateLinkage)
return ctorFunction
return ctor
}
//-------------------------------------------------------------------------//
@@ -623,16 +624,6 @@ internal class CodeGeneratorVisitor(
override fun visitConstructor(declaration: IrConstructor) {
context.log{"visitConstructor : ${ir2string(declaration)}"}
if (declaration.constructedClass.isInlined()) {
// Do not generate any ctors for value types.
return
}
if (declaration.isObjCConstructor) {
// Do not generate any ctors for external Objective-C classes.
return
}
visitFunction(declaration)
}
@@ -709,12 +700,12 @@ internal class CodeGeneratorVisitor(
private inner class FunctionScope private constructor(
val functionGenerationContext: FunctionGenerationContext,
val declaration: IrFunction?,
val llvmFunction: LLVMValueRef) : InnerScopeImpl() {
val llvmFunction: LlvmCallable) : InnerScopeImpl() {
constructor(declaration: IrFunction, functionGenerationContext: FunctionGenerationContext) :
this(functionGenerationContext, declaration, codegen.llvmFunction(declaration).llvmValue)
this(functionGenerationContext, declaration, codegen.llvmFunction(declaration))
constructor(llvmFunction: LLVMValueRef, functionGenerationContext: FunctionGenerationContext) :
constructor(llvmFunction: LlvmCallable, functionGenerationContext: FunctionGenerationContext) :
this(functionGenerationContext, null, llvmFunction)
val coverageInstrumentation: LLVMCoverageInstrumentation? =
@@ -796,12 +787,10 @@ internal class CodeGeneratorVisitor(
override fun visitFunction(declaration: IrFunction) {
context.log{"visitFunction : ${ir2string(declaration)}"}
val body = declaration.body
val scopeState = llvm.initializersGenerationState.scopeState
if (declaration.origin == DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER) {
require(scopeState.globalInitFunction == null) { "There can only be at most one global file initializer" }
require(body == null) { "The body of file initializer should be null" }
require(declaration.body == null) { "The body of file initializer should be null" }
require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" }
require(declaration.returnsUnit()) { "File initializer must return Unit" }
scopeState.globalInitFunction = declaration
@@ -810,7 +799,7 @@ internal class CodeGeneratorVisitor(
if (declaration.origin == DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|| declaration.origin == DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER) {
require(scopeState.threadLocalInitFunction == null) { "There can only be at most one thread local file initializer" }
require(body == null) { "The body of file initializer should be null" }
require(declaration.body == null) { "The body of file initializer should be null" }
require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" }
require(declaration.returnsUnit()) { "File initializer must return Unit" }
scopeState.threadLocalInitFunction = declaration
@@ -818,10 +807,10 @@ internal class CodeGeneratorVisitor(
}
if ((declaration as? IrSimpleFunction)?.modality == Modality.ABSTRACT
|| declaration.isExternal
|| body == null)
if (!declaration.shouldGenerateBody())
return
// Some special functions may have empty body, thay are handled separetely.
val body = declaration.body ?: return
val file = if (declaration.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA)
null
else ((declaration as? IrSimpleFunction)?.attributeOwnerId as? IrSimpleFunction)?.let { context.irLinker.getFileOf(it) }?.takeIf {
@@ -860,7 +849,7 @@ internal class CodeGeneratorVisitor(
if (declaration.retainAnnotation(context.config.target)) {
llvm.usedFunctions.add(codegen.llvmFunction(declaration).llvmValue)
llvm.usedFunctions.add(codegen.llvmFunction(declaration))
}
if (context.shouldVerifyBitCode())
@@ -2237,8 +2226,8 @@ internal class CodeGeneratorVisitor(
isReifiedInline -> null
// TODO: May be tie up inline lambdas to their outer function?
codegen.isExternal(this) && !KonanBinaryInterface.isExported(this) -> null
this is IrSimpleFunction && isSuspend -> this.getOrCreateFunctionWithContinuationStub(context).let { codegen.llvmFunctionOrNull(it)?.llvmValue }
else -> codegen.llvmFunctionOrNull(this)?.llvmValue
this is IrSimpleFunction && isSuspend -> this.getOrCreateFunctionWithContinuationStub(context).let { codegen.llvmFunctionOrNull(it) }
else -> codegen.llvmFunctionOrNull(this)
}
return with(debugInfo) {
val f = this@scope
@@ -2249,7 +2238,7 @@ internal class CodeGeneratorVisitor(
val subroutineType = subroutineType(codegen.llvmTargetData)
diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType, nodebug).also {
if (!this@scope.isInline)
DIFunctionAddSubprogram(functionLlvmValue, it)
functionLlvmValue.addDebugInfoSubprogram(it)
}
}
} as DIScopeOpaqueRef
@@ -2266,10 +2255,10 @@ internal class CodeGeneratorVisitor(
}
@Suppress("UNCHECKED_CAST")
private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean): DIScopeOpaqueRef? {
private fun LlvmCallable.scope(startLine:Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean): DIScopeOpaqueRef? {
return debugInfo.subprograms.getOrPut(this) {
diFunctionScope(name!!, name!!, startLine, subroutineType, nodebug).also {
DIFunctionAddSubprogram(this@scope, it)
this@scope.addDebugInfoSubprogram(it)
}
} as DIScopeOpaqueRef
}
@@ -2425,7 +2414,7 @@ internal class CodeGeneratorVisitor(
private fun evaluateFileGlobalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
val statePtr = getGlobalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.asCallback() }
val bbInit = basicBlock("label_init", null)
val bbExit = basicBlock("label_continue", null)
@@ -2445,7 +2434,7 @@ internal class CodeGeneratorVisitor(
val globalStatePtr = getGlobalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
val localState = getThreadLocalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
val localStatePtr = localState.getAddress(functionGenerationContext)
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.asCallback() }
val bbInit = basicBlock("label_init", null)
val bbCheckLocalState = basicBlock("label_check_local", null)
@@ -2471,7 +2460,7 @@ internal class CodeGeneratorVisitor(
private fun evaluateFileStandaloneThreadLocalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
val state = getThreadLocalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
val statePtr = state.getAddress(functionGenerationContext)
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.asCallback() }
val bbInit = basicBlock("label_init", null)
val bbExit = basicBlock("label_continue", null)
@@ -2544,8 +2533,9 @@ internal class CodeGeneratorVisitor(
val protocolGetterName = annotation.getAnnotationStringValue("protocolGetter")
val protocolGetterProto = LlvmFunctionProto(
protocolGetterName,
LlvmRetType(llvm.int8PtrType),
LlvmFunctionSignature(LlvmRetType(llvm.int8PtrType)),
origin = FunctionOrigin.OwnedBy(irClass),
linkage = LLVMLinkage.LLVMExternalLinkage,
independent = true // Protocol is header-only declaration.
)
val protocolGetter = llvm.externalFunction(protocolGetterProto)
@@ -2758,12 +2748,12 @@ internal class CodeGeneratorVisitor(
//-------------------------------------------------------------------------//
// Create type { i32, void ()*, i8* }
val kCtorType = llvm.structType(llvm.int32Type, pointerType(kVoidFuncType), llvm.int8PtrType)
val kCtorType = llvm.structType(llvm.int32Type, pointerType(ctorFunctionSignature.llvmFunctionType), llvm.int8PtrType)
//-------------------------------------------------------------------------//
// Create object { i32, void ()*, i8* } { i32 1, void ()* @ctorFunction, i8* null }
fun createGlobalCtor(ctorFunction: LLVMValueRef): ConstPointer {
fun createGlobalCtor(ctorFunction: LlvmCallable): ConstPointer {
val priority = if (context.config.target.family == Family.MINGW) {
// Workaround MinGW bug. Using this value makes the compiler generate
// '.ctors' section instead of '.ctors.XXXXX', which can't be recognized by ld
@@ -2777,7 +2767,7 @@ internal class CodeGeneratorVisitor(
llvm.kImmInt32One
}
val data = llvm.kNullInt8Ptr
val argList = cValuesOf(priority, ctorFunction, data)
val argList = cValuesOf(priority, ctorFunction.toConstPointer().llvm, data)
val ctorItem = LLVMConstNamedStruct(kCtorType, argList, 3)!!
return constPointer(ctorItem)
}
@@ -2787,7 +2777,7 @@ internal class CodeGeneratorVisitor(
// Note: the list of libraries is topologically sorted (in order for initializers to be called correctly).
val dependencies = (generationState.dependenciesTracker.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */)
val libraryToInitializers = dependencies.associate { it?.library to mutableListOf<LLVMValueRef>() }
val libraryToInitializers = dependencies.associate { it?.library to mutableListOf<LlvmCallable>() }
llvm.irStaticInitializers.forEach {
val library = it.konanLibrary
@@ -2799,13 +2789,9 @@ internal class CodeGeneratorVisitor(
fun fileCtorName(libraryName: String, fileName: String) = "$libraryName:$fileName".moduleConstructorName
fun addCtorFunction(ctorName: String) =
addLlvmFunctionWithDefaultAttributes(
generationState.context,
llvm.module,
ctorName,
kVoidFuncType
).also { LLVMSetLinkage(it, LLVMLinkage.LLVMExternalLinkage) }
fun ctorProto(ctorName: String): LlvmFunctionProto {
return ctorFunctionSignature.toProto(ctorName, null, LLVMLinkage.LLVMExternalLinkage)
}
val ctorFunctions = dependencies.flatMap { dependency ->
val library = dependency?.library
@@ -2823,10 +2809,9 @@ internal class CodeGeneratorVisitor(
if (library == null || generationState.llvmModuleSpecification.containsLibrary(library)) {
val otherInitializers = llvm.otherStaticInitializers.takeIf { library == null }.orEmpty()
val ctorFunction = addCtorFunction(ctorName)
appendStaticInitializers(ctorFunction, initializers + otherInitializers)
listOf(ctorFunction)
listOf(
appendStaticInitializers(ctorProto(ctorName), initializers + otherInitializers)
)
} else {
// A cached library.
check(initializers.isEmpty()) {
@@ -2837,7 +2822,7 @@ internal class CodeGeneratorVisitor(
?: error("Library ${library.libraryFile} is expected to be cached")
when (cache) {
is CachedLibraries.Cache.Monolithic -> listOf(addCtorFunction(ctorName))
is CachedLibraries.Cache.Monolithic -> listOf(ctorProto(ctorName))
is CachedLibraries.Cache.PerFile -> {
val files = when (dependency.kind) {
is DependenciesTracker.DependencyKind.WholeModule ->
@@ -2845,8 +2830,10 @@ internal class CodeGeneratorVisitor(
is DependenciesTracker.DependencyKind.CertainFiles ->
dependency.kind.files
}
files.map { addCtorFunction(fileCtorName(library.uniqueName, it)) }
files.map { ctorProto(fileCtorName(library.uniqueName, it)) }
}
}.map {
codegen.addFunction(it)
}
}
}
@@ -2854,9 +2841,9 @@ internal class CodeGeneratorVisitor(
appendGlobalCtors(ctorFunctions)
}
private fun appendStaticInitializers(ctorFunction: LLVMValueRef, initializers: List<LLVMValueRef>) {
generateFunctionNoRuntime(codegen, ctorFunction) {
val initGuardName = ctorFunction.name.orEmpty() + "_guard"
private fun appendStaticInitializers(ctorCallableProto: LlvmFunctionProto, initializers: List<LlvmCallable>) : LlvmCallable {
return generateFunctionNoRuntime(codegen, ctorCallableProto) {
val initGuardName = function.name.orEmpty() + "_guard"
val initGuard = LLVMAddGlobal(llvm.module, llvm.int32Type, initGuardName)
LLVMSetInitializer(initGuard, llvm.kImmInt32Zero)
LLVMSetLinkage(initGuard, LLVMLinkage.LLVMPrivateLinkage)
@@ -2884,27 +2871,30 @@ internal class CodeGeneratorVisitor(
}
}
private fun appendGlobalCtors(ctorFunctions: List<LLVMValueRef>) {
private fun appendGlobalCtors(ctorFunctions: List<LlvmCallable>) {
if (context.config.isFinalBinary) {
// Generate function calling all [ctorFunctions].
val globalCtorFunction = generateFunctionNoRuntime(codegen, kVoidFuncType, "_Konan_constructors") {
val ctorProto = ctorFunctionSignature.toProto(
name = "_Konan_constructors",
origin = null,
linkage = if (context.config.produce == CompilerOutputKind.PROGRAM) LLVMLinkage.LLVMExternalLinkage else LLVMLinkage.LLVMPrivateLinkage
)
val globalCtorCallable = generateFunctionNoRuntime(codegen, ctorProto) {
ctorFunctions.forEach {
call(it, emptyList(), Lifetime.IRRELEVANT,
exceptionHandler = ExceptionHandler.Caller, verbatim = true)
}
ret(null)
}
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage)
// Append initializers of global variables in "llvm.global_ctors" array.
val globalCtors = codegen.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
listOf(createGlobalCtor(globalCtorFunction)))
listOf(createGlobalCtor(globalCtorCallable)))
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
if (context.config.produce == CompilerOutputKind.PROGRAM) {
// Provide an optional handle for calling .ctors, if standard constructors mechanism
// is not available on the platform (i.e. WASM, embedded).
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMExternalLinkage)
appendLlvmUsed("llvm.used", listOf(globalCtorFunction))
appendLlvmUsed("llvm.used", listOf(globalCtorCallable.toConstPointer().llvm))
}
}
}
@@ -87,7 +87,7 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native
.distinctBy { it.selector }
allInitMethodsInfo.mapTo(this) {
ObjCMethodDesc(it.selector, it.encoding, llvm.missingInitImp.llvmValue)
ObjCMethodDesc(it.selector, it.encoding, llvm.missingInitImp.toConstPointer())
}
}
@@ -108,10 +108,10 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native
private val impType = pointerType(functionType(llvm.int8PtrType, true, llvm.int8PtrType, llvm.int8PtrType))
private inner class ObjCMethodDesc(
val selector: String, val encoding: String, val impFunction: LLVMValueRef
val selector: String, val encoding: String, val impFunction: ConstPointer
) : Struct(
runtime.objCMethodDescription,
constPointer(impFunction).bitcast(impType),
impFunction.bitcast(impType),
staticData.cStringLiteral(selector),
staticData.cStringLiteral(encoding)
)
@@ -126,7 +126,7 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native
ObjCMethodDesc(
annotation.getAnnotationStringValue("selector"),
annotation.getAnnotationStringValue("encoding"),
it.llvmFunction.llvmValue
it.llvmFunction.toConstPointer()
)
}
@@ -136,16 +136,19 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native
Zero(runtime.kotlinObjCClassData)
).pointer
val functionType = functionType(classDataPointer.llvmType, false, llvm.int8PtrType, llvm.int8PtrType)
val functionName = "kobjcclassdataimp:${irClass.fqNameForIrSerialization}#internal"
val function = generateFunctionNoRuntime(codegen, functionType, functionName) {
val functionProto = LlvmFunctionSignature(
returnType = LlvmRetType(classDataPointer.llvmType),
parameterTypes = listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType)),
).toProto(
name = "kobjcclassdataimp:${irClass.fqNameForIrSerialization}#internal",
origin = null,
LLVMLinkage.LLVMPrivateLinkage
)
val functionCallable = generateFunctionNoRuntime(codegen, functionProto) {
ret(classDataPointer.llvm)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMPrivateLinkage)
}
return constPointer(function)
return functionCallable.toConstPointer()
}
private val codegen = CodeGenerator(generationState)
@@ -11,21 +11,12 @@ import org.jetbrains.kotlin.konan.target.Architecture
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.KonanTarget
internal fun addLlvmFunctionWithDefaultAttributes(
context: Context,
module: LLVMModuleRef,
name: String,
type: LLVMTypeRef
): LLVMValueRef = LLVMAddFunction(module, name, type)!!.also {
addDefaultLlvmFunctionAttributes(context, it)
addTargetCpuAndFeaturesAttributes(context, it)
}
/**
* Mimics parts of clang's `CodeGenModule::getDefaultFunctionAttributes`
* that are required for Kotlin/Native compiler.
*/
private fun addDefaultLlvmFunctionAttributes(context: Context, llvmFunction: LLVMValueRef) {
internal fun addDefaultLlvmFunctionAttributes(context: Context, llvmFunction: LLVMValueRef) {
if (shouldEnforceFramePointer(context)) {
// Note: this is default for clang on at least on iOS and macOS.
enforceFramePointer(llvmFunction, context)
@@ -35,7 +26,7 @@ private fun addDefaultLlvmFunctionAttributes(context: Context, llvmFunction: LLV
/**
* Set target cpu and its features to make LLVM generate correct machine code.
*/
private fun addTargetCpuAndFeaturesAttributes(context: Context, llvmFunction: LLVMValueRef) {
internal fun addTargetCpuAndFeaturesAttributes(context: Context, llvmFunction: LLVMValueRef) {
context.config.platform.targetCpu?.let {
LLVMAddTargetDependentFunctionAttr(llvmFunction, "target-cpu", it)
}
@@ -5,19 +5,85 @@
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMGetReturnType
import llvm.LLVMTypeRef
import llvm.LLVMValueRef
import kotlinx.cinterop.toCValues
import llvm.*
/**
* Wrapper around LLVM value of functional type.
*
* @todo This class mixes "something that can be called" and function abstractions.
* Some of it's methods make sense only for functions. Probably, LlvmFunction sub-class should be extracted.
*/
class LlvmCallable(val llvmValue: LLVMValueRef, val attributeProvider: LlvmFunctionAttributeProvider) {
class LlvmCallable(private val llvmValue: LLVMValueRef, private val attributeProvider: LlvmFunctionAttributeProvider) {
val returnType: LLVMTypeRef by lazy {
LLVMGetReturnType(functionType)!!
}
val name by lazy {
llvmValue.name
}
val functionType: LLVMTypeRef by lazy {
getFunctionType(llvmValue)
}
val numParams by lazy {
LLVMCountParams(llvmValue)
}
val pgoFunctionNameVar by lazy {
LLVMCreatePGOFunctionNameVar(llvmValue, name)!!
}
val isConstant by lazy {
LLVMIsConstant(llvmValue) == 1
}
fun buildCall(builder: LLVMBuilderRef, args: List<LLVMValueRef>, name: String = "") =
LLVMBuildCall(builder, llvmValue, args.toCValues(), args.size, name)!!.also {
attributeProvider.addCallSiteAttributes(it)
}
fun buildInvoke(builder: LLVMBuilderRef, args: List<LLVMValueRef>, success: LLVMBasicBlockRef, catch: LLVMBasicBlockRef, name: String = "") =
LLVMBuildInvoke(builder, llvmValue, args.toCValues(), args.size, success, catch, name)!!.also {
attributeProvider.addCallSiteAttributes(it)
}
fun buildLandingpad(builder: LLVMBuilderRef, landingpadType: LLVMTypeRef, numClauses: Int, name: String = "") =
LLVMBuildLandingPad(builder, landingpadType, llvmValue, numClauses, name)!!
fun addBasicBlock(context: LLVMContextRef, name: String = "") =
LLVMAppendBasicBlockInContext(context, llvmValue, name)!!
fun blockAddress(label: LLVMBasicBlockRef) = LLVMBlockAddress(llvmValue, label)!!
fun addDebugInfoSubprogram(subprogram: DISubprogramRef) {
DIFunctionAddSubprogram(llvmValue, subprogram)
}
fun createBridgeFunctionDebugInfo(builder: DIBuilderRef, scope: DIScopeOpaqueRef, file: DIFileRef, lineNo: Int, type: DISubroutineTypeRef, isLocal: Int, isDefinition: Int, scopeLine: Int) =
DICreateBridgeFunction(
builder = builder,
scope = scope,
function = llvmValue,
file = file,
lineNo = lineNo,
type = type,
isLocal = isLocal,
isDefinition = isDefinition,
scopeLine = scopeLine
)!!
fun param(i: Int) : LLVMValueRef {
require(i in 0 until numParams)
return LLVMGetParam(llvmValue, i)!!
}
val isNoUnwind by lazy {
LLVMIsAFunction(llvmValue) != null && isFunctionNoUnwind(llvmValue)
}
// these functions are potentially unsafe, as they need to use same attribute provider when converted to callable
internal fun toConstPointer() = constPointer(llvmValue)
internal fun asCallback() = llvmValue
}
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
import org.jetbrains.kotlin.backend.konan.descriptors.requiredAlignment
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.lower.isStaticInitializer
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
@@ -352,10 +354,6 @@ private class DeclarationsGeneratorVisitor(override val generationState: NativeG
if (!declaration.isReal) return
if ((declaration is IrConstructor && declaration.isObjCConstructor)) {
return
}
val llvmFunction = if (declaration.isExternal) {
if (declaration.isTypedIntrinsic || declaration.isObjCBridgeBased()
// All call-sites to external accessors to interop properties
@@ -363,9 +361,12 @@ private class DeclarationsGeneratorVisitor(override val generationState: NativeG
|| (declaration.isAccessor && declaration.isFromInteropLibrary())
|| declaration.annotations.hasAnnotation(RuntimeNames.cCall)) return
val proto = LlvmFunctionProto(declaration, declaration.computeSymbolName(), this)
val proto = LlvmFunctionProto(declaration, declaration.computeSymbolName(), this, LLVMLinkage.LLVMExternalLinkage)
llvm.externalFunction(proto)
} else {
if (!declaration.shouldGenerateBody()) {
return
}
val symbolName = if (declaration.isExported()) {
declaration.computeSymbolName().also {
if (declaration.name.asString() != "main") {
@@ -385,16 +386,13 @@ private class DeclarationsGeneratorVisitor(override val generationState: NativeG
}
}
val proto = LlvmFunctionProto(declaration, symbolName, this)
val llvmFunction = addLlvmFunctionWithDefaultAttributes(
context,
llvm.module,
symbolName,
proto.llvmFunctionType
).also {
proto.addFunctionAttributes(it)
val linkage = when {
declaration.isExported() -> LLVMLinkage.LLVMExternalLinkage
context.config.producePerFileCache && declaration in generationState.calledFromExportedInlineFunctions -> LLVMLinkage.LLVMExternalLinkage
else -> LLVMLinkage.LLVMInternalLinkage
}
LlvmCallable(llvmFunction, proto)
val proto = LlvmFunctionProto(declaration, symbolName, this, linkage)
proto.createLlvmFunction(context, llvm.module)
}
declaration.metadata = KonanMetadata.Function(declaration, llvmFunction)
@@ -158,31 +158,35 @@ sealed class FunctionOrigin {
* Prototype of a LLVM function that is not tied to a specific LLVM module.
*/
internal class LlvmFunctionProto(
val name: String,
returnType: LlvmRetType,
parameterTypes: List<LlvmParamType> = emptyList(),
functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
val origin: FunctionOrigin,
isVararg: Boolean = false,
val independent: Boolean = false,
) : LlvmFunctionSignature(returnType, parameterTypes, isVararg, functionAttributes) {
constructor(
name: String,
signature: LlvmFunctionSignature,
origin: FunctionOrigin,
independent: Boolean = false,
) : this(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, origin, signature.isVararg, independent)
constructor(irFunction: IrFunction, symbolName: String, contextUtils: ContextUtils) : this(
val name: String,
val signature: LlvmFunctionSignature,
val origin: FunctionOrigin?,
val linkage: LLVMLinkage,
val independent: Boolean = false,
) {
constructor(irFunction: IrFunction, symbolName: String, contextUtils: ContextUtils, linkage: LLVMLinkage) : this(
name = symbolName,
returnType = contextUtils.getLlvmFunctionReturnType(irFunction),
parameterTypes = contextUtils.getLlvmFunctionParameterTypes(irFunction),
functionAttributes = inferFunctionAttributes(contextUtils, irFunction),
signature = LlvmFunctionSignature(irFunction, contextUtils),
origin = FunctionOrigin.OwnedBy(irFunction),
linkage = linkage,
independent = irFunction.hasAnnotation(RuntimeNames.independent)
)
fun createLlvmFunction(context: Context, llvmModule: LLVMModuleRef): LlvmCallable {
val function = LLVMAddFunction(llvmModule, name, signature.llvmFunctionType)!!
addDefaultLlvmFunctionAttributes(context, function)
addTargetCpuAndFeaturesAttributes(context, function)
signature.addFunctionAttributes(function)
LLVMSetLinkage(function, linkage)
return LlvmCallable(function, signature)
}
}
internal fun LlvmFunctionSignature.toProto(name: String, origin: FunctionOrigin?, linkage: LLVMLinkage, independent: Boolean = false) =
LlvmFunctionProto(name, this, origin, linkage, independent)
private fun mustNotInline(context: Context, irFunction: IrFunction): Boolean {
if (context.shouldContainLocationDebugInfo()) {
if (irFunction is IrConstructor && irFunction.isPrimary && irFunction.returnType.isThrowable()) {
@@ -126,12 +126,6 @@ fun extractConstUnsignedInt(value: LLVMValueRef): Long {
return LLVMConstIntGetZExtValue(value)
}
internal fun ContextUtils.isObjectReturn(functionType: LLVMTypeRef) : Boolean {
// Note that type is usually function pointer, so we have to dereference it.
val returnType = LLVMGetReturnType(LLVMGetElementType(functionType))!!
return isObjectType(returnType)
}
internal fun ContextUtils.isObjectRef(value: LLVMValueRef): Boolean {
return isObjectType(value.type)
}
@@ -194,11 +188,15 @@ private fun CodeGenerator.replaceExternalWeakOrCommonGlobal(name: String, value:
// When some dynamic caches are used, we consider that stdlib is in the dynamic cache as well.
// Runtime is linked into stdlib module only, so import runtime global from it.
val global = importGlobal(name, value.llvmType)
val initializer = generateFunctionNoRuntime(this, functionType(llvm.voidType, false), "") {
val initializerProto = LlvmFunctionSignature(LlvmRetType(llvm.voidType)).toProto(
name = "",
origin = null,
LLVMLinkage.LLVMPrivateLinkage
)
val initializer = generateFunctionNoRuntime(this, initializerProto) {
store(value.llvm, global)
ret(null)
}
LLVMSetLinkage(initializer, LLVMLinkage.LLVMPrivateLinkage)
llvm.otherStaticInitializers += initializer
} else {
@@ -262,7 +262,7 @@ internal class RTTIGenerator(
llvmDeclarations.writableTypeInfoGlobal?.pointer,
associatedObjects = genAssociatedObjects(irClass),
processObjectInMark = when {
irClass.symbol == context.ir.symbols.array -> constPointer(llvm.Kotlin_processArrayInMark.llvmValue)
irClass.symbol == context.ir.symbols.array -> llvm.Kotlin_processArrayInMark.toConstPointer()
else -> genProcessObjectInMark(bodyType)
},
requiredAlignment = llvmDeclarations.alignment
@@ -469,9 +469,9 @@ internal class RTTIGenerator(
val associatedObjectTableRecords = associatedObjects.map { (key, value) ->
val function = context.getObjectClassInstanceFunction(value)
val llvmFunction = generationState.llvmDeclarations.forFunction(function).llvmValue
val llvmFunction = generationState.llvmDeclarations.forFunction(function)
Struct(runtime.associatedObjectTableRecordType, key.typeInfoPtr, constPointer(llvmFunction))
Struct(runtime.associatedObjectTableRecordType, key.typeInfoPtr, llvmFunction.toConstPointer())
}
return staticData.placeGlobalConstArray(
@@ -486,11 +486,11 @@ internal class RTTIGenerator(
return when {
indicesOfObjectFields.isEmpty() -> {
// TODO: Try to generate it here instead of importing from the runtime.
constPointer(llvm.Kotlin_processEmptyObjectInMark.llvmValue)
llvm.Kotlin_processEmptyObjectInMark.toConstPointer()
}
else -> {
// TODO: specialize for "small" objects
constPointer(llvm.Kotlin_processObjectInMark.llvmValue)
llvm.Kotlin_processObjectInMark.toConstPointer()
}
}
}
@@ -6,7 +6,7 @@ package org.jetbrains.kotlin.backend.konan.llvm.coverage
import llvm.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.llvm.LlvmCallable
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -88,7 +88,7 @@ internal class CoverageManager(val generationState: NativeGenerationState) {
/**
* @return [LLVMCoverageInstrumentation] instance if [irFunction] should be covered.
*/
fun tryGetInstrumentation(irFunction: IrFunction?, callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit) =
fun tryGetInstrumentation(irFunction: IrFunction?, callSitePlacer: (function: LlvmCallable, args: List<LLVMValueRef>) -> Unit) =
if (enabled && irFunction != null) {
getFunctionRegions(irFunction)?.let { LLVMCoverageInstrumentation(generationState, it, callSitePlacer) }
} else {
@@ -21,13 +21,21 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
internal class LLVMCoverageInstrumentation(
override val generationState: NativeGenerationState,
private val functionRegions: FunctionRegions,
private val callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit
private val callSitePlacer: (function: LlvmCallable, args: List<LLVMValueRef>) -> Unit
) : ContextUtils {
private val functionNameGlobal = createFunctionNameGlobal(functionRegions.function)
private val functionHash = llvm.int64(functionRegions.structuralHash)
private val instrProfIncrement by lazy {
val incrementFun = LLVMInstrProfIncrement(llvm.module)!!
LlvmCallable(
incrementFun,
LlvmFunctionAttributeProvider.copyFromExternal(incrementFun)
)
}
// TODO: It's a great place for some debug output.
fun instrumentIrElement(element: IrElement) {
functionRegions.regions[element]?.let {
@@ -42,13 +50,12 @@ internal class LLVMCoverageInstrumentation(
val numberOfRegions = llvm.int32(functionRegions.regions.size)
val regionNumber = llvm.int32(functionRegions.regionEnumeration.getValue(region))
val args = listOf(functionNameGlobal, functionHash, numberOfRegions, regionNumber)
callSitePlacer(LLVMInstrProfIncrement(llvm.module)!!, args)
callSitePlacer(instrProfIncrement, args)
}
// Each profiled function should have a global with its name in a specific format.
private fun createFunctionNameGlobal(function: IrFunction): LLVMValueRef {
val name = function.llvmFunction.llvmValue.name
val pgoFunctionName = LLVMCreatePGOFunctionNameVar(function.llvmFunction.llvmValue, name)!!
val pgoFunctionName = function.llvmFunction.pgoFunctionNameVar
return LLVMConstBitCast(pgoFunctionName, llvm.int8PtrType)!!
}
}
@@ -54,7 +54,7 @@ internal class LLVMCoverageWriter(
fileIds.toCValues(), fileIds.size.signExtend(),
regions.toCValues(), regions.size.signExtend())
val functionName = generationState.llvmDeclarations.forFunction(functionRegions.function).llvmValue.name
val functionName = generationState.llvmDeclarations.forFunction(functionRegions.function).name
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(generationState.llvm.module),
functionName, functionRegions.structuralHash, functionCoverage)!!
@@ -27,14 +27,12 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
return load(classRef.llvm)
}
private val objcMsgSend = constPointer(
llvm.externalNativeRuntimeFunction(
private val objcMsgSend = llvm.externalNativeRuntimeFunction(
"objc_msgSend",
LlvmRetType(llvm.int8PtrType),
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType)),
isVararg = true
).llvmValue
)
).toConstPointer()
val objcRelease = llvm.externalNativeRuntimeFunction(
"llvm.objc.release",
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
bridge: BlockPointerBridge
): LLVMValueRef {
): LlvmCallable {
val irInterface = symbols.functionN(bridge.numberOfParameters).owner
val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
.single { it.name == OperatorNameConventions.INVOKE }
@@ -33,8 +33,11 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
}
val invokeImpl = functionGenerator(
LlvmFunctionSignature(invokeMethod, codegen),
"invokeFunction${bridge.nameSuffix}"
LlvmFunctionSignature(invokeMethod, codegen).toProto(
"invokeFunction${bridge.nameSuffix}",
null,
LLVMLinkage.LLVMInternalLinkage
)
).generate {
val thisRef = param(0)
val associatedObjectHolder = if (useSeparateHolder) {
@@ -80,19 +83,17 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
.also { objcReleaseFromRunnableThreadState(result) }
}
ret(kotlinResult)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
val typeInfo = rttiGenerator.generateSyntheticInterfaceImpl(
irInterface,
mapOf(invokeMethod to constPointer(invokeImpl)),
mapOf(invokeMethod to invokeImpl.toConstPointer()),
bodyType,
immutable = true
)
val functionSig = LlvmFunctionSignature(LlvmRetType(codegen.kObjHeaderPtr), listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(codegen.kObjHeaderPtrPtr)))
return functionGenerator(
LlvmFunctionSignature(LlvmRetType(codegen.kObjHeaderPtr), listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(codegen.kObjHeaderPtrPtr))),
"convertBlock${bridge.nameSuffix}"
functionSig.toProto("convertBlock${bridge.nameSuffix}", null, LLVMLinkage.LLVMInternalLinkage)
).generate {
val blockPtr = param(0)
ifThen(icmpEq(blockPtr, llvm.kNullInt8Ptr)) {
@@ -116,18 +117,17 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
}
ret(result)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
}
private fun FunctionGenerationContext.loadBlockInvoke(
blockPtr: LLVMValueRef,
bridge: BlockPointerBridge
): LLVMValueRef {
): LlvmCallable {
val invokePtr = structGep(bitcast(pointerType(codegen.runtime.blockLiteralType), blockPtr), 3)
val signature = bridge.blockType.toBlockInvokeLlvmType(llvm)
return bitcast(pointerType(bridge.blockType.toBlockInvokeLlvmType(llvm).llvmFunctionType), load(invokePtr))
return LlvmCallable(bitcast(pointerType(signature.llvmFunctionType), load(invokePtr)), signature)
}
private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
@@ -165,10 +165,18 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
codegen.runtime.kRefSharedHolderType
)
val disposeProto = LlvmFunctionSignature(
LlvmRetType(llvm.voidType),
listOf(LlvmParamType(llvm.int8PtrType))
).toProto(
"blockDisposeHelper",
null,
LLVMLinkage.LLVMInternalLinkage
)
val disposeHelper = generateFunction(
codegen,
functionType(llvm.voidType, false, llvm.int8PtrType),
"blockDisposeHelper",
disposeProto,
switchToRunnable = true
) {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
@@ -176,14 +184,20 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
call(llvm.kRefSharedHolderDispose, listOf(refHolder))
ret(null)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
val copyProto = LlvmFunctionSignature(
LlvmRetType(llvm.voidType),
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType))
).toProto(
"blockCopyHelper",
null,
LLVMLinkage.LLVMInternalLinkage
)
val copyHelper = generateFunction(
codegen,
functionType(llvm.voidType, false, llvm.int8PtrType, llvm.int8PtrType),
"blockCopyHelper"
copyProto,
) {
val dstBlockPtr = bitcast(pointerType(blockLiteralType), param(0))
val dstRefHolder = structGep(dstBlockPtr, 1)
@@ -204,8 +218,6 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
call(llvm.kRefSharedHolderInit, listOf(dstRefHolder, ref))
ret(null)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
fun CodeGenerator.LongInt(value: Long) =
@@ -236,8 +248,8 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
return Struct(codegen.runtime.blockDescriptorType,
codegen.LongInt(0L),
codegen.LongInt(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)),
constPointer(copyHelper),
constPointer(disposeHelper),
copyHelper.toConstPointer(),
disposeHelper.toConstPointer(),
codegen.staticData.cStringLiteral(signature),
NullPointer(llvm.int8Type)
)
@@ -249,7 +261,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
invokeName: String,
genBody: ObjCExportFunctionGenerationContext.(LLVMValueRef, List<LLVMValueRef>) -> Unit
): ConstPointer {
val result = functionGenerator(blockType.toBlockInvokeLlvmType(llvm), invokeName) {
val result = functionGenerator(blockType.toBlockInvokeLlvmType(llvm).toProto(invokeName, null, LLVMLinkage.LLVMInternalLinkage)) {
switchToRunnable = true
}.generate {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
@@ -263,16 +275,14 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
val arguments = (1 .. blockType.numberOfParameters).map { index -> param(index) }
genBody(kotlinObject, arguments)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
return constPointer(result)
return result.toConstPointer()
}
fun ObjCExportCodeGeneratorBase.generateConvertFunctionToRetainedBlock(
bridge: BlockPointerBridge
): LLVMValueRef {
): LlvmCallable {
return generateWrapKotlinObjectToRetainedBlock(
bridge.blockType,
convertName = "convertFunction${bridge.nameSuffix}",
@@ -299,15 +309,16 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
convertName: String,
invokeName: String,
genBlockBody: ObjCExportFunctionGenerationContext.(LLVMValueRef, List<LLVMValueRef>) -> Unit
): LLVMValueRef {
): LlvmCallable {
val blockDescriptor = codegen.staticData.placeGlobal(
"",
generateDescriptorForBlock(blockType)
)
return functionGenerator(
LlvmFunctionSignature(LlvmRetType(llvm.int8PtrType), listOf(LlvmParamType(codegen.kObjHeaderPtr))),
convertName
LlvmFunctionSignature(LlvmRetType(llvm.int8PtrType), listOf(LlvmParamType(codegen.kObjHeaderPtr))).toProto(
convertName, null, LLVMLinkage.LLVMInternalLinkage
)
).generate {
val kotlinRef = param(0)
ifThen(icmpEq(kotlinRef, kNullObjHeaderPtr)) {
@@ -338,8 +349,6 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
val copiedBlock = callFromBridge(retainBlock, listOf(bitcast(llvm.int8PtrType, blockOnStack)))
ret(copiedBlock)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
}
}
@@ -111,19 +111,12 @@ internal class ObjCExportFunctionGenerationContext(
}
internal class ObjCExportFunctionGenerationContextBuilder(
functionType: LlvmFunctionSignature,
functionName: String,
functionProto: LlvmFunctionProto,
val objCExportCodegen: ObjCExportCodeGeneratorBase
) : FunctionGenerationContextBuilder<ObjCExportFunctionGenerationContext>(
functionType.llvmFunctionType,
functionName,
functionProto,
objCExportCodegen.codegen
) {
// Not a very pleasant way to provide attributes to the generated function.
init {
functionType.addFunctionAttributes(function)
}
// Unless specified otherwise, all generated bridges by ObjCExport should have `LeaveFrame`
// because there is no guarantee of catching Kotlin exception in Kotlin code.
var needCleanupLandingpadAndLeaveFrame = true
@@ -132,24 +125,22 @@ internal class ObjCExportFunctionGenerationContextBuilder(
}
internal inline fun ObjCExportCodeGeneratorBase.functionGenerator(
functionType: LlvmFunctionSignature,
functionName: String,
functionProto: LlvmFunctionProto,
configure: ObjCExportFunctionGenerationContextBuilder.() -> Unit = {}
): ObjCExportFunctionGenerationContextBuilder = ObjCExportFunctionGenerationContextBuilder(
functionType,
functionName,
functionProto,
this
).apply(configure)
internal fun ObjCExportFunctionGenerationContext.callAndMaybeRetainAutoreleased(
function: LLVMValueRef,
function: LlvmCallable,
signature: LlvmFunctionSignature,
args: List<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
exceptionHandler: ExceptionHandler,
doRetain: Boolean
): LLVMValueRef {
if (!doRetain) return call(function, args, resultLifetime, exceptionHandler, attributeProvider = signature)
if (!doRetain) return call(function, args, resultLifetime, exceptionHandler)
// Objective-C runtime provides "optimizable" return for autoreleased references:
// the caller (this code) handles the return value with objc_retainAutoreleasedReturnValue,
@@ -170,15 +161,16 @@ internal fun ObjCExportFunctionGenerationContext.callAndMaybeRetainAutoreleased(
// and catch the exceptions in the caller of this function.
// So, no exception handler in "outlined" => no redundant jump => the optimized return works properly.
val functionIsPassedAsLastParameter = LLVMIsConstant(function) == 0
val functionIsPassedAsLastParameter = !function.isConstant
val valuesToPass = args + if (functionIsPassedAsLastParameter) listOf(function) else emptyList()
val valuesToPass = args + if (functionIsPassedAsLastParameter) listOf(function.asCallback()) else emptyList()
val outlinedType = LlvmFunctionSignature(
signature.returnType,
signature.parameterTypes + if (functionIsPassedAsLastParameter) listOf(LlvmParamType(function.type)) else emptyList()
signature.parameterTypes + if (functionIsPassedAsLastParameter) listOf(LlvmParamType(pointerType(function.functionType))) else emptyList(),
functionAttributes = listOf(LlvmFunctionAttribute.NoInline)
)
val outlined = objCExportCodegen.functionGenerator(outlinedType, this.function.name.orEmpty() + "_outlined") {
val outlined = objCExportCodegen.functionGenerator(outlinedType.toProto( this.function.name.orEmpty() + "_outlined", null, LLVMLinkage.LLVMPrivateLinkage)) {
setupBridgeDebugInfo()
// Don't generate redundant cleanup landingpad (the generation would fail due to forbidRuntime below):
needCleanupLandingpadAndLeaveFrame = false
@@ -186,12 +178,10 @@ internal fun ObjCExportFunctionGenerationContext.callAndMaybeRetainAutoreleased(
forbidRuntime = true // Don't emit safe points, frame management etc.
val actualArgs = signature.parameterTypes.indices.map { param(it) }
val actualFunction = if (functionIsPassedAsLastParameter) param(signature.parameterTypes.size) else function
val actualCallable = if (functionIsPassedAsLastParameter) LlvmCallable(param(signature.parameterTypes.size), signature) else function
// Use LLVMBuildCall instead of call, because the latter enforces using exception handler, which is exactly what we have to avoid.
val result = LLVMBuildCall(builder, actualFunction, actualArgs.toCValues(), actualArgs.size, "")!!.also {
signature.addCallSiteAttributes(it)
}.let { callResult ->
val result = actualCallable.buildCall(builder, actualArgs).let { callResult ->
// Simplified version of emitAutoreleasedReturnValueMarker in Clang:
objCExportCodegen.objcRetainAutoreleasedReturnValueMarker?.let {
LLVMBuildCall(arg0 = builder, Fn = it, Args = null, NumArgs = 0, Name = "")
@@ -206,11 +196,8 @@ internal fun ObjCExportFunctionGenerationContext.callAndMaybeRetainAutoreleased(
ret(result)
}
outlinedType.addFunctionAttributes(outlined)
LLVMSetLinkage(outlined, LLVMLinkage.LLVMPrivateLinkage)
setFunctionNoInline(outlined)
return call(LlvmCallable(outlined, outlinedType), valuesToPass, resultLifetime, exceptionHandler)
return call(outlined, valuesToPass, resultLifetime, exceptionHandler)
}
internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCodeGenerator(codegen) {
@@ -258,17 +245,17 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
fun ObjCExportFunctionGenerationContext.objCReferenceToKotlin(value: LLVMValueRef, resultLifetime: Lifetime) =
callFromBridge(llvm.Kotlin_ObjCExport_refFromObjC, listOf(value), resultLifetime)
private val blockToKotlinFunctionConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>()
private val blockToKotlinFunctionConverterCache = mutableMapOf<BlockPointerBridge, LlvmCallable>()
internal fun blockToKotlinFunctionConverter(bridge: BlockPointerBridge): LLVMValueRef =
internal fun blockToKotlinFunctionConverter(bridge: BlockPointerBridge): LlvmCallable =
blockToKotlinFunctionConverterCache.getOrPut(bridge) {
generateBlockToKotlinFunctionConverter(bridge)
}
protected val blockGenerator = BlockGenerator(this.codegen)
private val functionToRetainedBlockConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>()
private val functionToRetainedBlockConverterCache = mutableMapOf<BlockPointerBridge, LlvmCallable>()
internal fun kotlinFunctionToRetainedBlockConverter(bridge: BlockPointerBridge): LLVMValueRef =
internal fun kotlinFunctionToRetainedBlockConverter(bridge: BlockPointerBridge): LlvmCallable =
functionToRetainedBlockConverterCache.getOrPut(bridge) {
blockGenerator.run {
generateConvertFunctionToRetainedBlock(bridge)
@@ -312,13 +299,11 @@ internal class ObjCExportCodeGenerator(
val selectorsToDefine = mutableMapOf<String, MethodBridge>()
val externalGlobalInitializers = mutableMapOf<LLVMValueRef, ConstValue>()
internal val continuationToRetainedCompletionConverter: LLVMValueRef by lazy {
internal val continuationToRetainedCompletionConverter: LlvmCallable by lazy {
generateContinuationToRetainedCompletionConverter(blockGenerator)
}
internal val unitContinuationToRetainedCompletionConverter: LLVMValueRef by lazy {
internal val unitContinuationToRetainedCompletionConverter: LlvmCallable by lazy {
generateUnitContinuationToRetainedCompletionConverter(blockGenerator)
}
@@ -564,15 +549,17 @@ internal class ObjCExportCodeGenerator(
)
private fun emitSelectorsHolder() {
val impType = functionType(llvm.voidType, false, llvm.int8PtrType, llvm.int8PtrType)
val imp = generateFunctionNoRuntime(codegen, impType, "") {
val impProto = LlvmFunctionSignature(LlvmRetType(llvm.voidType)).toProto(
name = "",
origin = null,
linkage = LLVMLinkage.LLVMInternalLinkage
)
val imp = generateFunctionNoRuntime(codegen, impProto) {
unreachable()
}
LLVMSetLinkage(imp, LLVMLinkage.LLVMInternalLinkage)
val methods = selectorsToDefine.map { (selector, bridge) ->
ObjCDataGenerator.Method(selector, getEncoding(bridge), constPointer(imp))
ObjCDataGenerator.Method(selector, getEncoding(bridge), imp.toConstPointer())
}
dataGenerator.emitClass(
@@ -754,7 +741,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(
val boxClass = boxClassSymbol.owner
val name = "${boxClass.name}ToNSNumber"
val converter = functionGenerator(kotlinToObjCFunctionType, name).generate {
val converter = functionGenerator(kotlinToObjCFunctionType.toProto(name, null, LLVMLinkage.LLVMPrivateLinkage)).generate {
val unboxFunction = context.getUnboxFunction(boxClass).llvmFunction
val kotlinValue = callFromBridge(
unboxFunction,
@@ -774,13 +761,12 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(
ret(genSendMessage(returnType, valueParameterTypes, instance, nsNumberInitSelector, value))
}
LLVMSetLinkage(converter, LLVMLinkage.LLVMPrivateLinkage)
setObjCExportTypeInfo(boxClass, constPointer(converter))
setObjCExportTypeInfo(boxClass, converter.toConstPointer())
}
private fun ObjCExportCodeGenerator.generateContinuationToRetainedCompletionConverter(
blockGenerator: BlockGenerator
): LLVMValueRef = with(blockGenerator) {
): LlvmCallable = with(blockGenerator) {
generateWrapKotlinObjectToRetainedBlock(
BlockType(numberOfParameters = 2, returnsVoid = true),
convertName = "convertContinuation",
@@ -798,7 +784,7 @@ private fun ObjCExportCodeGenerator.generateContinuationToRetainedCompletionConv
private fun ObjCExportCodeGenerator.generateUnitContinuationToRetainedCompletionConverter(
blockGenerator: BlockGenerator
): LLVMValueRef = with(blockGenerator) {
): LlvmCallable = with(blockGenerator) {
generateWrapKotlinObjectToRetainedBlock(
BlockType(numberOfParameters = 1, returnsVoid = true),
convertName = "convertUnitContinuation",
@@ -827,7 +813,7 @@ private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
mappedFunctionNClasses.forEach { functionClass ->
val convertToRetained = kotlinFunctionToRetainedBlockConverter(BlockPointerBridge(functionClass.arity, returnsVoid = false))
val writableTypeInfoValue = buildWritableTypeInfoValue(convertToRetained = constPointer(convertToRetained))
val writableTypeInfoValue = buildWritableTypeInfoValue(convertToRetained = convertToRetained.toConstPointer())
setOwnWritableTypeInfo(functionClass.irClass, writableTypeInfoValue)
}
}
@@ -841,7 +827,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
val converters = (0 until arityLimit).map { arity ->
functionClassesByArity[arity]?.let {
val bridge = BlockPointerBridge(numberOfParameters = arity, returnsVoid = false)
constPointer(blockToKotlinFunctionConverter(bridge))
blockToKotlinFunctionConverter(bridge).toConstPointer()
} ?: NullPointer(objCToKotlinFunctionType)
}
@@ -859,7 +845,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
setObjCExportTypeInfo(
symbols.string.owner,
constPointer(llvm.Kotlin_ObjCExport_CreateRetainedNSStringFromKString.llvmValue)
llvm.Kotlin_ObjCExport_CreateRetainedNSStringFromKString.toConstPointer()
)
emitCollectionConverters()
@@ -870,7 +856,7 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
private fun ObjCExportCodeGenerator.emitCollectionConverters() {
fun importConverter(name: String): ConstPointer =
constPointer(llvm.externalNativeRuntimeFunction(name, kotlinToObjCFunctionType).llvmValue)
llvm.externalNativeRuntimeFunction(name, kotlinToObjCFunctionType).toConstPointer()
setObjCExportTypeInfo(
symbols.list.owner,
@@ -914,10 +900,10 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
debugInfo: Boolean = false,
suffix: String,
genBody: ObjCExportFunctionGenerationContext.() -> Unit
): LLVMValueRef {
): LlvmCallable {
val functionType = objCFunctionType(generationState, methodBridge)
val functionName = "objc2kotlin_$suffix"
val result = functionGenerator(functionType, functionName) {
val result = functionGenerator(functionType.toProto(functionName, null, LLVMLinkage.LLVMInternalLinkage)) {
if (debugInfo) {
this.setupBridgeDebugInfo()
}
@@ -926,12 +912,10 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
}.generate {
genBody()
}
LLVMSetLinkage(result, LLVMLinkage.LLVMInternalLinkage)
return result
}
private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: MethodBridge, baseMethod: IrFunction): LLVMValueRef =
private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: MethodBridge, baseMethod: IrFunction): LlvmCallable =
generateObjCImpBy(methodBridge, suffix = baseMethod.computeSymbolName()) {
callFromBridge(
llvm.Kotlin_ObjCExport_AbstractMethodCalled,
@@ -980,7 +964,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
resultLifetime: Lifetime,
exceptionHandler: ExceptionHandler
) -> LLVMValueRef?
): LLVMValueRef = generateObjCImpBy(
): LlvmCallable = generateObjCImpBy(
methodBridge,
debugInfo = isDirect /* see below */,
suffix = bridgeSuffix,
@@ -1168,7 +1152,7 @@ private fun ObjCExportCodeGenerator.effectiveThrowsClasses(method: IrFunction, s
private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
target: IrConstructor,
methodBridge: MethodBridge
): LLVMValueRef = generateObjCImp(methodBridge, bridgeSuffix = target.computeSymbolName(), isDirect = true) { args, resultLifetime, exceptionHandler ->
): LlvmCallable = generateObjCImp(methodBridge, bridgeSuffix = target.computeSymbolName(), isDirect = true) { args, resultLifetime, exceptionHandler ->
val arrayInstance = callFromBridge(
llvm.allocArrayFunction,
listOf(target.constructedClass.llvmTypeInfoPtr, args.first()),
@@ -1192,7 +1176,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
val functionType = LlvmFunctionSignature(irFunction, codegen)
val functionName = "kotlin2objc_${baseIrFunction.computeSymbolName()}"
val result = functionGenerator(functionType, functionName).generate {
val result = functionGenerator(functionType.toProto(functionName, null, LLVMLinkage.LLVMInternalLinkage)).generate {
var errorOutPtr: LLVMValueRef? = null
val parameters = irFunction.allParameters.mapIndexed { index, parameterDescriptor ->
@@ -1286,7 +1270,7 @@ 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 = callAndMaybeRetainAutoreleased(
objcMsgSend.llvmValue,
objcMsgSend,
objCFunctionType,
objCArgs,
exceptionHandler = terminatingExceptionHandler,
@@ -1403,9 +1387,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
ret(retVal)
}
LLVMSetLinkage(result, LLVMLinkage.LLVMInternalLinkage)
return constPointer(result)
return result.toConstPointer()
}
private fun MethodBridge.ReturnValue.isAutoreleasedObjCReference(): Boolean = when (this) {
@@ -1827,25 +1809,23 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
val functionType = objCFunctionType(generationState, methodBridge)
val functionName = "objc2kotlin_$suffix"
val imp = functionGenerator(functionType, functionName) {
val imp = functionGenerator(functionType.toProto(functionName, null, LLVMLinkage.LLVMInternalLinkage)) {
switchToRunnable = true
}.generate {
block()
}
LLVMSetLinkage(imp, LLVMLinkage.LLVMInternalLinkage)
return objCToKotlinMethodAdapter(selector, methodBridge, imp)
}
private fun ObjCExportCodeGenerator.objCToKotlinMethodAdapter(
selector: String,
methodBridge: MethodBridge,
imp: LLVMValueRef
imp: LlvmCallable
): ObjCExportCodeGenerator.ObjCToKotlinMethodAdapter {
selectorsToDefine[selector] = methodBridge
return ObjCToKotlinMethodAdapter(selector, getEncoding(methodBridge), constPointer(imp))
return ObjCToKotlinMethodAdapter(selector, getEncoding(methodBridge), imp.toConstPointer())
}
private fun ObjCExportCodeGenerator.createUnitInstanceAdapter(selector: String) =