diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CheckExternalCalls.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CheckExternalCalls.kt index c5159328b52..582e1448c21 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CheckExternalCalls.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CheckExternalCalls.kt @@ -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) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cexport/CAdapterCodegen.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cexport/CAdapterCodegen.kt index 0cfa573950e..5fb8a522588 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cexport/CAdapterCodegen.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/cexport/CAdapterCodegen.kt @@ -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))) } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index d0b33a19e2e..d4b7cf7f16a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -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 FunctionGenerationContextBuilder.generate(code: T.() -> Unit): LLVMValueRef { +internal inline fun FunctionGenerationContextBuilder.generate(code: T.() -> Unit): LlvmCallable { val functionGenerationContext = this.build() return try { generateFunctionBody(functionGenerationContext, code) @@ -149,12 +143,13 @@ internal inline fun 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( - 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>, - val argsNumber: Int, + val llvmFunction: LlvmCallable, + val args: List, val success: LLVMBasicBlockRef, - val attributeProvider: LlvmFunctionAttributeProvider? ) private val invokeInstructions = mutableListOf() @@ -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, - 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, - 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, + 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?, diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index b9d2c3a29e7..f6eb976763c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -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 = 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() + val usedFunctions = mutableListOf() val usedGlobals = mutableListOf() val compilerUsedGlobals = mutableListOf() val irStaticInitializers = mutableListOf() - val otherStaticInitializers = mutableListOf() - val globalSharedObjects = mutableSetOf() + val otherStaticInitializers = mutableListOf() val initializersGenerationState = InitializersGenerationState() val boxCacheGlobals = mutableMapOf() @@ -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) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt index 2c0d9eb754d..99d8655c002 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt @@ -132,7 +132,7 @@ internal class DebugInfo(override val generationState: NativeGenerationState) : } val files = mutableMapOf() - val subprograms = mutableMapOf() + val subprograms = mutableMapOf() /* Some functions are inlined on all callsites and body is eliminated by DCE, so there's no LLVM value */ val inlinedSubprograms = mutableMapOf() @@ -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) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index af261c412fe..0fe8796cb6b 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -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 = "" )!! diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 801368cf482..f002f2846ec 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -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?) : 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() } + val libraryToInitializers = dependencies.associate { it?.library to mutableListOf() } 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) { - generateFunctionNoRuntime(codegen, ctorFunction) { - val initGuardName = ctorFunction.name.orEmpty() + "_guard" + private fun appendStaticInitializers(ctorCallableProto: LlvmFunctionProto, initializers: List) : 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) { + private fun appendGlobalCtors(ctorFunctions: List) { 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)) } } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt index d7ac3b307b1..3239fe18901 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt @@ -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) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmAttributes.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmAttributes.kt index 1f2b2213745..9f272586c3a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmAttributes.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmAttributes.kt @@ -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) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmCallable.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmCallable.kt index c4c692f3d08..d85328916ba 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmCallable.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmCallable.kt @@ -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, name: String = "") = + LLVMBuildCall(builder, llvmValue, args.toCValues(), args.size, name)!!.also { + attributeProvider.addCallSiteAttributes(it) + } + + fun buildInvoke(builder: LLVMBuilderRef, args: List, 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 } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt index f5f75b53b05..261fc7ec307 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt @@ -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) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt index cf98db6e518..897f6756ee4 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt @@ -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 = emptyList(), - functionAttributes: List = 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()) { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index 06b1766221c..6f9b59c1ab7 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt @@ -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 { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index c5025c717c7..92811760d46 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -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() } } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt index 6c20775f53d..91bd7619dcf 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt @@ -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) -> Unit) = + fun tryGetInstrumentation(irFunction: IrFunction?, callSitePlacer: (function: LlvmCallable, args: List) -> Unit) = if (enabled && irFunction != null) { getFunctionRegions(irFunction)?.let { LLVMCoverageInstrumentation(generationState, it, callSitePlacer) } } else { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageInstrumentation.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageInstrumentation.kt index 1ad7279458c..fa089bce5e7 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageInstrumentation.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageInstrumentation.kt @@ -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) -> Unit + private val callSitePlacer: (function: LlvmCallable, args: List) -> 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)!! } } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageWriter.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageWriter.kt index 38612d83d9c..a4f3d764e53 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageWriter.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/LLVMCoverageWriter.kt @@ -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)!! diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCCodeGenerator.kt index 8070f5d5a95..08d7a3baff3 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCCodeGenerator.kt @@ -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", diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt index afaf917cf92..21c92b7d731 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt @@ -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() .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) -> 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) -> 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) } } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 173f8e27bdf..23a7c8f2ac9 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -111,19 +111,12 @@ internal class ObjCExportFunctionGenerationContext( } internal class ObjCExportFunctionGenerationContextBuilder( - functionType: LlvmFunctionSignature, - functionName: String, + functionProto: LlvmFunctionProto, val objCExportCodegen: ObjCExportCodeGeneratorBase ) : FunctionGenerationContextBuilder( - 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, 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() + private val blockToKotlinFunctionConverterCache = mutableMapOf() - 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() + private val functionToRetainedBlockConverterCache = mutableMapOf() - 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() - val externalGlobalInitializers = mutableMapOf() - - 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) =