[K/N] LLVM attributes at call-sites
(I messed up commit history and all changes had to be squashed. Sorry.) The commit is originated from KT-48591. The root of the problem is following: we unconditionally added sext to all value parameters of imported functions. To fix this problem we have to pass zext/sext depending on the parameter type. To make things right and future-proof, we decided to refactor a significant part of IR to bitcode translator: when generating callsite compiler "looks" at callee and applies its attributes to the callsite. There are several sources of attributes: 1. External LLVM functions from runtime: just copy-paste attributes. 2. Direct IR calls: infer attributes from the declaration. 3. Virtual calls: use available declaration, so almost the same as prev. 4. External declarations functions: manual labor! Specifying attributes at all callsites (including Kotlin->Kotlin) makes things uniform and a little easier to implement. All in all, the delta is significant, but comprehensible. In some places I managed to make it seamless by changing declaration type and its usages types simultaneously. In others (ObjCExport), unfortunately, things got a little messy. #KT-48722 fixed
This commit is contained in:
+7
-6
@@ -212,21 +212,22 @@ private class ExportedElement(val kind: ElementKind,
|
||||
val function = declaration as FunctionDescriptor
|
||||
val irFunction = irSymbol.owner as IrFunction
|
||||
cname = "_konan_function_${owner.nextFunctionIndex()}"
|
||||
val llvmFunction = owner.codegen.llvmFunction(irFunction)
|
||||
val llvmCallable = owner.codegen.llvmFunction(irFunction)
|
||||
// If function is virtual, we need to resolve receiver properly.
|
||||
val bridge = if (!DescriptorUtils.isTopLevelDeclaration(function) &&
|
||||
irFunction.isOverridable) {
|
||||
// We need LLVMGetElementType() as otherwise type is function pointer.
|
||||
generateFunction(owner.codegen, LLVMGetElementType(llvmFunction.type)!!, cname) {
|
||||
generateFunction(owner.codegen, llvmCallable.functionType, cname) {
|
||||
val receiver = param(0)
|
||||
val numParams = LLVMCountParams(llvmFunction)
|
||||
val args = (0 .. numParams - 1).map { index -> param(index) }
|
||||
val numParams = LLVMCountParams(llvmCallable.llvmValue)
|
||||
val args = (0..numParams - 1).map { index -> param(index) }
|
||||
val callee = lookupVirtualImpl(receiver, irFunction)
|
||||
callee.attributeProvider.addFunctionAttributes(this.function)
|
||||
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
||||
ret(result)
|
||||
}
|
||||
} else {
|
||||
LLVMAddAlias(context.llvmModule, llvmFunction.type, llvmFunction, cname)!!
|
||||
val aliasType = pointerType(llvmCallable.functionType)
|
||||
LLVMAddAlias(context.llvmModule, aliasType, llvmCallable.llvmValue, cname)!!
|
||||
}
|
||||
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
|
||||
}
|
||||
|
||||
+25
-10
@@ -38,15 +38,30 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun externalFunction(name: String, type: LLVMTypeRef) =
|
||||
context.llvm.externalFunction(name, type, context.stdlibModule.llvmSymbolOrigin)
|
||||
|
||||
private fun moduleFunction(name: String) =
|
||||
LLVMGetNamedFunction(context.llvmModule, name) ?: throw IllegalStateException("$name function is not available")
|
||||
|
||||
val getMethodImpl = externalFunction("class_getMethodImplementation", functionType(pointerType(functionType(voidType, false)), false, int8TypePtr, int8TypePtr))
|
||||
val getClass = externalFunction("object_getClass", functionType(int8TypePtr, false, int8TypePtr))
|
||||
val getSuperClass = externalFunction("class_getSuperclass", functionType(int8TypePtr, false, int8TypePtr))
|
||||
val getMethodImpl = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"class_getMethodImplementation",
|
||||
LlvmRetType(pointerType(functionType(voidType, false))),
|
||||
listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin)
|
||||
)
|
||||
|
||||
val getClass = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"object_getClass",
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin)
|
||||
)
|
||||
|
||||
val getSuperClass = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"class_getSuperclass",
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin)
|
||||
)
|
||||
|
||||
val checkerFunction = moduleFunction("Kotlin_mm_checkStateAtExternalFunctionCall")
|
||||
|
||||
private data class ExternalCallInfo(val name: String?, val calledPtr: LLVMValueRef)
|
||||
@@ -102,10 +117,10 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
|
||||
callSiteDescription = "$functionName (over objc_msgSend)"
|
||||
calledName = null
|
||||
val firstArgI8Ptr = LLVMBuildBitCast(builder, LLVMGetArgOperand(call, 0), int8TypePtr, "")
|
||||
val firstArgClassPtr = LLVMBuildCall(builder, getClass, listOf(firstArgI8Ptr).toCValues(), 1, "")
|
||||
val firstArgClassPtr = LLVMBuildCall(builder, getClass.llvmValue, listOf(firstArgI8Ptr).toCValues(), 1, "")
|
||||
val isNil = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, firstArgI8Ptr, LLVMConstNull(int8TypePtr), "")
|
||||
val selector = LLVMGetArgOperand(call, 1)
|
||||
val calledPtrLlvmIfNotNilFunPtr = LLVMBuildCall(builder, getMethodImpl, listOf(firstArgClassPtr, selector).toCValues(), 2, "")
|
||||
val calledPtrLlvmIfNotNilFunPtr = LLVMBuildCall(builder, getMethodImpl.llvmValue, listOf(firstArgClassPtr, selector).toCValues(), 2, "")
|
||||
val calledPtrLlvmIfNotNil = LLVMBuildBitCast(builder, calledPtrLlvmIfNotNilFunPtr, int8TypePtr, "")
|
||||
val calledPtrLlvmIfNil = LLVMConstIntToPtr(Int64(MSG_SEND_TO_NULL).llvm, int8TypePtr)
|
||||
calledPtrLlvm = LLVMBuildSelect(builder, isNil, calledPtrLlvmIfNil, calledPtrLlvmIfNotNil, "")
|
||||
@@ -117,8 +132,8 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
|
||||
val superStruct = LLVMGetArgOperand(call, 0)
|
||||
val superClassPtrPtr = LLVMBuildGEP(builder, superStruct, listOf(Int32(0).llvm, Int32(1).llvm).toCValues(), 2, "")
|
||||
val superClassPtr = LLVMBuildLoad(builder, superClassPtrPtr, "")
|
||||
val classPtr = LLVMBuildCall(builder, getSuperClass, listOf(superClassPtr).toCValues(), 1, "")
|
||||
val calledPtrLlvmFunPtr = LLVMBuildCall(builder, getMethodImpl, listOf(classPtr, LLVMGetArgOperand(call, 1)).toCValues(), 2, "")
|
||||
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, int8TypePtr, "")
|
||||
}
|
||||
else -> {
|
||||
|
||||
+7
-1
@@ -52,6 +52,12 @@ internal inline fun <R> KotlinType.unwrapToPrimitiveOrReference(
|
||||
ifReference: (type: KotlinType) -> R
|
||||
): R = KotlinTypeInlineClassesSupport.unwrapToPrimitiveOrReference(this, eachInlinedClass, ifPrimitive, ifReference)
|
||||
|
||||
internal inline fun <R> IrType.unwrapToPrimitiveOrReference(
|
||||
eachInlinedClass: (inlinedClass: IrClass, nullable: Boolean) -> Unit,
|
||||
ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
|
||||
ifReference: (type: IrType) -> R
|
||||
): R = IrTypeInlineClassesSupport.unwrapToPrimitiveOrReference(this, eachInlinedClass, ifPrimitive, ifReference)
|
||||
|
||||
// TODO: consider renaming to `isReference`.
|
||||
fun KotlinType.binaryTypeIsReference(): Boolean = this.computePrimitiveBinaryTypeOrNull() == null
|
||||
fun IrType.binaryTypeIsReference(): Boolean = this.computePrimitiveBinaryTypeOrNull() == null
|
||||
@@ -263,7 +269,7 @@ internal object KotlinTypeInlineClassesSupport : InlineClassesSupport<ClassDescr
|
||||
override fun isTopLevelClass(clazz: ClassDescriptor): Boolean = clazz.containingDeclaration is PackageFragmentDescriptor
|
||||
}
|
||||
|
||||
private object IrTypeInlineClassesSupport : InlineClassesSupport<IrClass, IrType>() {
|
||||
internal object IrTypeInlineClassesSupport : InlineClassesSupport<IrClass, IrType>() {
|
||||
|
||||
override fun isNullable(type: IrType): Boolean = type.containsNull()
|
||||
|
||||
|
||||
+5
-13
@@ -129,19 +129,11 @@ private fun String.replaceSpecialSymbols() =
|
||||
fun IrDeclaration.isExported() = KonanBinaryInterface.isExported(this)
|
||||
|
||||
// TODO: bring here dependencies of this method?
|
||||
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
|
||||
val returnType = when {
|
||||
function is IrConstructor -> voidType
|
||||
function.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
|
||||
else -> getLLVMReturnType(function.returnType)
|
||||
}
|
||||
val paramTypes = ArrayList(function.allParameters.map { getLLVMType(it.type) })
|
||||
if (function.isSuspend)
|
||||
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
|
||||
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
||||
|
||||
return functionType(returnType, isVarArg = false, paramTypes = paramTypes.toTypedArray())
|
||||
}
|
||||
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef = functionType(
|
||||
returnType = getLlvmFunctionReturnType(function).llvmType,
|
||||
isVarArg = false,
|
||||
paramTypes = getLlvmFunctionParameterTypes(function).map { it.llvmType }
|
||||
)
|
||||
|
||||
internal val IrClass.typeInfoHasVtableAttached: Boolean
|
||||
get() = !this.isAbstract() && !this.isExternalObjCClass()
|
||||
|
||||
+51
-25
@@ -48,9 +48,13 @@ internal fun IrClass.hasConstStateAndNoSideEffects(context: Context): Boolean {
|
||||
}
|
||||
|
||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
fun llvmFunction(function: IrFunction): LlvmCallable =
|
||||
llvmFunctionOrNull(function)
|
||||
?: error("no function ${function.name} in ${function.file.fqName}")
|
||||
|
||||
fun llvmFunctionOrNull(function: IrFunction): LlvmCallable? =
|
||||
function.llvmFunctionOrNull
|
||||
|
||||
fun llvmFunction(function: IrFunction): LLVMValueRef = llvmFunctionOrNull(function) ?: error("no function ${function.name} in ${function.file.fqName}")
|
||||
fun llvmFunctionOrNull(function: IrFunction): LLVMValueRef? = function.llvmFunctionOrNull
|
||||
val intPtrType = LLVMIntPtrTypeInContext(llvmContext, llvmTargetData)!!
|
||||
internal val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!!
|
||||
internal val immThreeIntPtrType = LLVMConstInt(intPtrType, 3, 1)!!
|
||||
@@ -63,10 +67,10 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun param(fn: IrFunction, i: Int): LLVMValueRef {
|
||||
assert(i >= 0 && i < countParams(fn))
|
||||
return LLVMGetParam(fn.llvmFunction, i)!!
|
||||
return LLVMGetParam(fn.llvmFunction.llvmValue, i)!!
|
||||
}
|
||||
|
||||
private fun countParams(fn: IrFunction) = LLVMCountParams(fn.llvmFunction)
|
||||
private fun countParams(fn: IrFunction) = LLVMCountParams(fn.llvmFunction.llvmValue)
|
||||
|
||||
fun functionEntryPointAddress(function: IrFunction) = function.entryPointAddress.llvm
|
||||
fun functionHash(function: IrFunction): LLVMValueRef = function.computeFunctionName().localHash.llvm
|
||||
@@ -128,7 +132,7 @@ internal inline fun generateFunction(
|
||||
endLocation: LocationInfo?,
|
||||
code: FunctionGenerationContext.() -> Unit
|
||||
) {
|
||||
val llvmFunction = codegen.llvmFunction(function)
|
||||
val llvmFunction = codegen.llvmFunction(function).llvmValue
|
||||
|
||||
val isCToKotlinBridge = function.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE
|
||||
|
||||
@@ -473,15 +477,21 @@ internal abstract class FunctionGenerationContext(
|
||||
|
||||
val stackLocalsManager = StackLocalsManagerImpl(this, stackLocalsInitBb)
|
||||
|
||||
data class FunctionInvokeInformation(val invokeInstruction: LLVMValueRef, val llvmFunction: LLVMValueRef, val rargs: CValues<CPointerVar<LLVMOpaqueValue>>,
|
||||
val argsNumber: Int, val success: LLVMBasicBlockRef)
|
||||
data class FunctionInvokeInformation(
|
||||
val invokeInstruction: LLVMValueRef,
|
||||
val llvmFunction: LLVMValueRef,
|
||||
val rargs: CValues<CPointerVar<LLVMOpaqueValue>>,
|
||||
val argsNumber: Int,
|
||||
val success: LLVMBasicBlockRef,
|
||||
val attributeProvider: LlvmFunctionAttributeProvider?
|
||||
)
|
||||
|
||||
private val invokeInstructions = mutableListOf<FunctionInvokeInformation>()
|
||||
|
||||
/**
|
||||
* TODO: consider merging this with [ExceptionHandler].
|
||||
*/
|
||||
var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null
|
||||
var forwardingForeignExceptionsTerminatedWith: LlvmCallable? = null
|
||||
|
||||
// Whether the generating function needs to initialize Kotlin runtime before execution. Useful for interop bridges,
|
||||
// for example.
|
||||
@@ -647,10 +657,18 @@ internal abstract class FunctionGenerationContext(
|
||||
Int32(size).llvm,
|
||||
Int1(isVolatile).llvm))
|
||||
|
||||
fun call(llvmCallable: LlvmCallable, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
|
||||
verbatim: Boolean = false): LLVMValueRef =
|
||||
call(llvmCallable.llvmValue, args, resultLifetime, exceptionHandler, verbatim, llvmCallable.attributeProvider)
|
||||
|
||||
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
|
||||
verbatim: Boolean = false): LLVMValueRef {
|
||||
verbatim: Boolean = false,
|
||||
attributeProvider: LlvmFunctionAttributeProvider? = null
|
||||
): LLVMValueRef {
|
||||
val callArgs = if (verbatim || !isObjectReturn(llvmFunction.type)) {
|
||||
args
|
||||
} else {
|
||||
@@ -677,15 +695,18 @@ internal abstract class FunctionGenerationContext(
|
||||
}
|
||||
args + resultSlot
|
||||
}
|
||||
return callRaw(llvmFunction, callArgs, exceptionHandler)
|
||||
return callRaw(llvmFunction, callArgs, exceptionHandler, attributeProvider)
|
||||
}
|
||||
|
||||
private fun callRaw(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
exceptionHandler: ExceptionHandler,
|
||||
attributeProvider: LlvmFunctionAttributeProvider?): LLVMValueRef {
|
||||
val rargs = args.toCValues()
|
||||
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
|
||||
isFunctionNoUnwind(llvmFunction)) {
|
||||
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!
|
||||
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!.also {
|
||||
attributeProvider?.addCallSiteAttributes(it)
|
||||
}
|
||||
} else {
|
||||
val unwind = when (exceptionHandler) {
|
||||
ExceptionHandler.Caller -> cleanupLandingpad
|
||||
@@ -706,11 +727,12 @@ internal abstract class FunctionGenerationContext(
|
||||
val endLocation = position?.end
|
||||
val success = basicBlock("call_success", endLocation)
|
||||
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!!
|
||||
attributeProvider?.addCallSiteAttributes(result)
|
||||
// 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))
|
||||
invokeInstructions.add(0, FunctionInvokeInformation(result, llvmFunction, rargs, args.size, success, attributeProvider))
|
||||
positionAtEnd(success)
|
||||
|
||||
return result
|
||||
@@ -867,7 +889,7 @@ internal abstract class FunctionGenerationContext(
|
||||
LLVMBuildExtractValue(builder, aggregate, index, name)!!
|
||||
|
||||
fun gxxLandingpad(numClauses: Int, name: String = ""): LLVMValueRef {
|
||||
val personalityFunction = context.llvm.gxxPersonalityFunction
|
||||
val personalityFunction = context.llvm.gxxPersonalityFunction.llvmValue
|
||||
|
||||
// Type of `landingpad` instruction result (depends on personality function):
|
||||
val landingpadType = structType(int8TypePtr, int32Type)
|
||||
@@ -1134,7 +1156,7 @@ internal abstract class FunctionGenerationContext(
|
||||
}
|
||||
}
|
||||
|
||||
fun lookupVirtualImpl(receiver: LLVMValueRef, irFunction: IrFunction): LLVMValueRef {
|
||||
fun lookupVirtualImpl(receiver: LLVMValueRef, irFunction: IrFunction): LlvmCallable {
|
||||
assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr)
|
||||
|
||||
val typeInfoPtr: LLVMValueRef = if (irFunction.getObjCMethodInfo() != null)
|
||||
@@ -1170,7 +1192,10 @@ internal abstract class FunctionGenerationContext(
|
||||
}
|
||||
}
|
||||
val functionPtrType = pointerType(codegen.getLlvmFunctionType(irFunction))
|
||||
return bitcast(functionPtrType, llvmMethod)
|
||||
return LlvmCallable(
|
||||
bitcast(functionPtrType, llvmMethod),
|
||||
LlvmFunctionSignature(irFunction, this)
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.findOverriddenMethodOfAny(): IrSimpleFunction? {
|
||||
@@ -1268,7 +1293,7 @@ internal abstract class FunctionGenerationContext(
|
||||
positionAtEnd(bbInit)
|
||||
val typeInfo = codegen.typeInfoForAllocation(irClass)
|
||||
val defaultConstructor = irClass.constructors.single { it.valueParameters.size == 0 }
|
||||
val ctor = codegen.llvmFunction(defaultConstructor)
|
||||
val ctor = codegen.llvmFunction(defaultConstructor).llvmValue
|
||||
val initFunction =
|
||||
if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) {
|
||||
context.llvm.initSingletonFunction
|
||||
@@ -1296,14 +1321,14 @@ internal abstract class FunctionGenerationContext(
|
||||
|
||||
val getterId = loweredEnum.entriesMap[enumEntry.name]!!.getterId
|
||||
val values = call(
|
||||
loweredEnum.valuesGetter.llvmFunction,
|
||||
loweredEnum.valuesGetter.llvmFunction.llvmValue,
|
||||
emptyList(),
|
||||
Lifetime.ARGUMENT,
|
||||
exceptionHandler
|
||||
)
|
||||
|
||||
return call(
|
||||
loweredEnum.itemGetterSymbol.owner.llvmFunction,
|
||||
loweredEnum.itemGetterSymbol.owner.llvmFunction.llvmValue,
|
||||
listOf(values, Int32(getterId).llvm),
|
||||
Lifetime.GLOBAL,
|
||||
exceptionHandler
|
||||
@@ -1321,12 +1346,12 @@ internal abstract class FunctionGenerationContext(
|
||||
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
|
||||
val objCClass = getObjCClass(name, llvmSymbolOrigin)
|
||||
|
||||
val getClass = context.llvm.externalFunction(
|
||||
val getClass = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"object_getClass",
|
||||
functionType(int8TypePtr, false, int8TypePtr),
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
|
||||
))
|
||||
call(getClass, listOf(objCClass), exceptionHandler = exceptionHandler)
|
||||
} else {
|
||||
getObjCClass(irClass.descriptor.getExternalObjCClassBinaryName(), llvmSymbolOrigin)
|
||||
@@ -1490,7 +1515,8 @@ internal abstract class FunctionGenerationContext(
|
||||
invokeInstructions.forEach { functionInvokeInfo ->
|
||||
positionBefore(functionInvokeInfo.invokeInstruction)
|
||||
val newResult = LLVMBuildCall(builder, functionInvokeInfo.llvmFunction, functionInvokeInfo.rargs,
|
||||
functionInvokeInfo.argsNumber, "")
|
||||
functionInvokeInfo.argsNumber, "")!!
|
||||
functionInvokeInfo.attributeProvider?.addCallSiteAttributes(newResult)
|
||||
// Have to generate `br` instruction because of current scheme of debug info.
|
||||
br(functionInvokeInfo.success)
|
||||
LLVMReplaceAllUsesWith(functionInvokeInfo.invokeInstruction, newResult)
|
||||
@@ -1531,7 +1557,7 @@ internal abstract class FunctionGenerationContext(
|
||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointFunctionEpilogue)
|
||||
}
|
||||
|
||||
private fun handleEpilogueForExperimentalMM(safePointFunction: LLVMValueRef) {
|
||||
private fun handleEpilogueForExperimentalMM(safePointFunction: LlvmCallable) {
|
||||
if (context.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
if (!forbidRuntime) {
|
||||
call(safePointFunction, emptyList())
|
||||
|
||||
+53
-80
@@ -5,9 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.allocArray
|
||||
import kotlinx.cinterop.get
|
||||
import kotlinx.cinterop.memScoped
|
||||
import kotlinx.cinterop.toKString
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.CachedLibraries
|
||||
@@ -170,19 +167,22 @@ internal interface ContextUtils : RuntimeAware {
|
||||
* LLVM function generated from the Kotlin function.
|
||||
* It may be declared as external function prototype.
|
||||
*/
|
||||
val IrFunction.llvmFunction: LLVMValueRef
|
||||
val IrFunction.llvmFunction: LlvmCallable
|
||||
get() = llvmFunctionOrNull
|
||||
?: error("$name in ${file.name}/${parent.fqNameForIrSerialization}")
|
||||
|
||||
val IrFunction.llvmFunctionOrNull: LLVMValueRef?
|
||||
val IrFunction.llvmFunctionOrNull: LlvmCallable?
|
||||
get() {
|
||||
assert(this.isReal)
|
||||
assert(this.isReal) {
|
||||
this.computeFullName()
|
||||
}
|
||||
return if (isExternal(this)) {
|
||||
runtime.addedLLVMExternalFunctions.getOrPut(this) { context.llvm.externalFunction(this.computeSymbolName(), getLlvmFunctionType(this),
|
||||
origin = this.llvmSymbolOrigin) }
|
||||
|
||||
runtime.addedLLVMExternalFunctions.getOrPut(this) {
|
||||
val proto = LlvmFunctionProto(this, this.computeSymbolName(), this@ContextUtils)
|
||||
context.llvm.externalFunction(proto)
|
||||
}
|
||||
} else {
|
||||
context.llvmDeclarations.forFunctionOrNull(this)?.llvmFunction
|
||||
context.llvmDeclarations.forFunctionOrNull(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ internal interface ContextUtils : RuntimeAware {
|
||||
*/
|
||||
val IrFunction.entryPointAddress: ConstPointer
|
||||
get() {
|
||||
val result = LLVMConstBitCast(this.llvmFunction, int8TypePtr)!!
|
||||
val result = LLVMConstBitCast(this.llvmFunction.llvmValue, int8TypePtr)!!
|
||||
return constPointer(result)
|
||||
}
|
||||
|
||||
@@ -256,19 +256,21 @@ internal class InitializersGenerationState {
|
||||
|
||||
internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : RuntimeAware {
|
||||
|
||||
private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
|
||||
private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable {
|
||||
if (LLVMGetNamedFunction(llvmModule, name) != null) {
|
||||
throw IllegalArgumentException("function $name already exists")
|
||||
}
|
||||
|
||||
val externalFunction = LLVMGetNamedFunction(otherModule, name) ?: throw Error("function $name not found")
|
||||
|
||||
val attributesCopier = LlvmFunctionAttributeProvider.copyFromExternal(externalFunction)
|
||||
|
||||
val functionType = getFunctionType(externalFunction)
|
||||
val function = LLVMAddFunction(llvmModule, name, functionType)!!
|
||||
|
||||
copyFunctionAttributes(externalFunction, function)
|
||||
attributesCopier.addFunctionAttributes(function)
|
||||
|
||||
return function
|
||||
return LlvmCallable(function, attributesCopier)
|
||||
}
|
||||
|
||||
private fun importGlobal(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
|
||||
@@ -283,74 +285,37 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
|
||||
return global
|
||||
}
|
||||
|
||||
private fun copyFunctionAttributes(source: LLVMValueRef, destination: LLVMValueRef) {
|
||||
// TODO: consider parameter attributes
|
||||
val attributeIndex = LLVMAttributeFunctionIndex
|
||||
val count = LLVMGetAttributeCountAtIndex(source, attributeIndex)
|
||||
memScoped {
|
||||
val attributes = allocArray<LLVMAttributeRefVar>(count)
|
||||
LLVMGetAttributesAtIndex(source, attributeIndex, attributes)
|
||||
(0 until count).forEach {
|
||||
LLVMAddAttributeAtIndex(destination, attributeIndex, attributes[it])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun importMemset(): LLVMValueRef {
|
||||
private fun importMemset(): LlvmCallable {
|
||||
val functionType = functionType(voidType, false, int8TypePtr, int8Type, int32Type, int1Type)
|
||||
return llvmIntrinsic("llvm.memset.p0i8.i32", functionType)
|
||||
}
|
||||
|
||||
private fun llvmIntrinsic(name: String, type: LLVMTypeRef, vararg attributes: String): LLVMValueRef {
|
||||
private fun llvmIntrinsic(name: String, type: LLVMTypeRef, vararg attributes: String): LlvmCallable {
|
||||
val result = LLVMAddFunction(llvmModule, name, type)!!
|
||||
attributes.forEach {
|
||||
val kindId = getLlvmAttributeKindId(it)
|
||||
addLlvmFunctionEnumAttribute(result, kindId)
|
||||
}
|
||||
return result
|
||||
return LlvmCallable(result, LlvmFunctionAttributeProvider.copyFromExternal(result))
|
||||
}
|
||||
|
||||
internal fun externalFunction(
|
||||
name: String,
|
||||
type: LLVMTypeRef,
|
||||
origin: CompiledKlibModuleOrigin,
|
||||
independent: Boolean = false
|
||||
): LLVMValueRef {
|
||||
this.imports.add(origin, onlyBitcode = independent)
|
||||
|
||||
val found = LLVMGetNamedFunction(llvmModule, name)
|
||||
internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable {
|
||||
this.imports.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent)
|
||||
val found = LLVMGetNamedFunction(llvmModule, llvmFunctionProto.name)
|
||||
if (found != null) {
|
||||
assert(getFunctionType(found) == type) {
|
||||
"Expected: ${LLVMPrintTypeToString(type)!!.toKString()} " +
|
||||
assert(getFunctionType(found) == llvmFunctionProto.llvmFunctionType) {
|
||||
"Expected: ${LLVMPrintTypeToString(llvmFunctionProto.llvmFunctionType)!!.toKString()} " +
|
||||
"found: ${LLVMPrintTypeToString(getFunctionType(found))!!.toKString()}"
|
||||
}
|
||||
assert(LLVMGetLinkage(found) == LLVMLinkage.LLVMExternalLinkage)
|
||||
return found
|
||||
return LlvmCallable(found, llvmFunctionProto)
|
||||
} else {
|
||||
// As exported functions are written in C++ they assume sign extension for promoted types -
|
||||
// mention that in attributes.
|
||||
val function = addLlvmFunctionWithDefaultAttributes(context, llvmModule, name, type)
|
||||
return memScoped {
|
||||
val paramCount = LLVMCountParamTypes(type)
|
||||
val paramTypes = allocArray<LLVMTypeRefVar>(paramCount)
|
||||
LLVMGetParamTypes(type, paramTypes)
|
||||
(0 until paramCount).forEach { index ->
|
||||
val paramType = paramTypes[index]
|
||||
addFunctionSignext(function, index + 1, paramType)
|
||||
}
|
||||
val returnType = LLVMGetReturnType(type)
|
||||
addFunctionSignext(function, 0, returnType)
|
||||
function
|
||||
}
|
||||
val function = addLlvmFunctionWithDefaultAttributes(context, llvmModule, llvmFunctionProto.name, llvmFunctionProto.llvmFunctionType)
|
||||
llvmFunctionProto.addFunctionAttributes(function)
|
||||
return LlvmCallable(function, llvmFunctionProto)
|
||||
}
|
||||
}
|
||||
|
||||
private fun externalNounwindFunction(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin): LLVMValueRef {
|
||||
val function = externalFunction(name, type, origin)
|
||||
setFunctionNoUnwind(function)
|
||||
return function
|
||||
}
|
||||
|
||||
val imports get() = context.llvmImports
|
||||
|
||||
class ImportsImpl(private val context: Context) : LlvmImports {
|
||||
@@ -563,27 +528,35 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
|
||||
else -> "__gxx_personality_v0"
|
||||
}
|
||||
|
||||
val cxxStdTerminate = externalNounwindFunction(
|
||||
val cxxStdTerminate = externalFunction(LlvmFunctionProto(
|
||||
"_ZSt9terminatev", // mangled C++ 'std::terminate'
|
||||
functionType(voidType, false),
|
||||
returnType = LlvmRetType(voidType),
|
||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
origin = context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
))
|
||||
|
||||
val gxxPersonalityFunction = externalNounwindFunction(
|
||||
val gxxPersonalityFunction = externalFunction(LlvmFunctionProto(
|
||||
personalityFunctionName,
|
||||
functionType(int32Type, true),
|
||||
returnType = LlvmRetType(int32Type),
|
||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
isVararg = true,
|
||||
origin = context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
val cxaBeginCatchFunction = externalNounwindFunction(
|
||||
))
|
||||
|
||||
val cxaBeginCatchFunction = externalFunction(LlvmFunctionProto(
|
||||
"__cxa_begin_catch",
|
||||
functionType(int8TypePtr, false, int8TypePtr),
|
||||
returnType = LlvmRetType(int8TypePtr),
|
||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
parameterTypes = listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
val cxaEndCatchFunction = externalNounwindFunction(
|
||||
))
|
||||
|
||||
val cxaEndCatchFunction = externalFunction(LlvmFunctionProto(
|
||||
"__cxa_end_catch",
|
||||
functionType(voidType, false),
|
||||
returnType = LlvmRetType(voidType),
|
||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
origin = context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
))
|
||||
|
||||
val memsetFunction = importMemset()
|
||||
//val memcpyFunction = importMemcpy()
|
||||
@@ -612,11 +585,11 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
|
||||
private object lazyRtFunction {
|
||||
operator fun provideDelegate(
|
||||
thisRef: Llvm, property: KProperty<*>
|
||||
) = object : ReadOnlyProperty<Llvm, LLVMValueRef> {
|
||||
) = object : ReadOnlyProperty<Llvm, LlvmCallable> {
|
||||
|
||||
val value by lazy { thisRef.importRtFunction(property.name) }
|
||||
val value: LlvmCallable by lazy { thisRef.importRtFunction(property.name) }
|
||||
|
||||
override fun getValue(thisRef: Llvm, property: KProperty<*>): LLVMValueRef = value
|
||||
override fun getValue(thisRef: Llvm, property: KProperty<*>): LlvmCallable = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,14 +612,14 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
|
||||
* Width of NSInteger in bits.
|
||||
*/
|
||||
val nsIntegerTypeWidth: Long by lazy {
|
||||
getSizeOfReturnTypeInBits(Kotlin_ObjCExport_NSIntegerTypeProvider)
|
||||
getSizeOfReturnTypeInBits(Kotlin_ObjCExport_NSIntegerTypeProvider.llvmValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of C long type in bits.
|
||||
*/
|
||||
val longTypeWidth: Long by lazy {
|
||||
getSizeOfReturnTypeInBits(Kotlin_longTypeProvider)
|
||||
getSizeOfReturnTypeInBits(Kotlin_longTypeProvider.llvmValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-9
@@ -454,25 +454,30 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
private fun FunctionGenerationContext.emitObjCGetMessenger(args: List<LLVMValueRef>, isStret: Boolean): LLVMValueRef {
|
||||
val messengerNameSuffix = if (isStret) "_stret" else ""
|
||||
|
||||
val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr)
|
||||
val functionReturnType = LlvmRetType(int8TypePtr)
|
||||
val functionParameterTypes = listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr))
|
||||
|
||||
val libobjc = context.standardLlvmSymbolsOrigin
|
||||
val normalMessenger = context.llvm.externalFunction(
|
||||
val normalMessenger = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"objc_msgSend$messengerNameSuffix",
|
||||
functionType,
|
||||
functionReturnType,
|
||||
functionParameterTypes,
|
||||
isVararg = true,
|
||||
origin = libobjc
|
||||
)
|
||||
val superMessenger = context.llvm.externalFunction(
|
||||
))
|
||||
val superMessenger = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"objc_msgSendSuper$messengerNameSuffix",
|
||||
functionType,
|
||||
functionReturnType,
|
||||
functionParameterTypes,
|
||||
isVararg = true,
|
||||
origin = libobjc
|
||||
)
|
||||
))
|
||||
|
||||
val superClass = args.single()
|
||||
val messenger = LLVMBuildSelect(builder,
|
||||
If = icmpEq(superClass, kNullInt8Ptr),
|
||||
Then = normalMessenger,
|
||||
Else = superMessenger,
|
||||
Then = normalMessenger.llvmValue,
|
||||
Else = superMessenger.llvmValue,
|
||||
Name = ""
|
||||
)!!
|
||||
|
||||
|
||||
+32
-32
@@ -712,7 +712,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
val llvmFunction: LLVMValueRef) : InnerScopeImpl() {
|
||||
|
||||
constructor(declaration: IrFunction, functionGenerationContext: FunctionGenerationContext) :
|
||||
this(functionGenerationContext, declaration, codegen.llvmFunction(declaration))
|
||||
this(functionGenerationContext, declaration, codegen.llvmFunction(declaration).llvmValue)
|
||||
|
||||
constructor(llvmFunction: LLVMValueRef, functionGenerationContext: FunctionGenerationContext) :
|
||||
this(functionGenerationContext, null, llvmFunction)
|
||||
@@ -857,7 +857,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
|
||||
if (declaration.retainAnnotation(context.config.target)) {
|
||||
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
|
||||
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration).llvmValue)
|
||||
}
|
||||
|
||||
if (context.shouldVerifyBitCode())
|
||||
@@ -1645,12 +1645,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
} else {
|
||||
// e.g. ObjCObject, ObjCObjectBase etc.
|
||||
if (dstClass.isObjCMetaClass()) {
|
||||
val isClass = context.llvm.externalFunction(
|
||||
val isClassProto = LlvmFunctionProto(
|
||||
"object_isClass",
|
||||
functionType(int8Type, false, int8TypePtr),
|
||||
context.standardLlvmSymbolsOrigin
|
||||
LlvmRetType(int8Type),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.standardLlvmSymbolsOrigin
|
||||
)
|
||||
|
||||
val isClass = context.llvm.externalFunction(isClassProto)
|
||||
call(isClass, listOf(objCObject)).let {
|
||||
functionGenerationContext.icmpNe(it, Int8(0).llvm)
|
||||
}
|
||||
@@ -2180,15 +2181,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
if (codegen.isExternal(this) && !KonanBinaryInterface.isExported(this))
|
||||
null
|
||||
else
|
||||
codegen.llvmFunctionOrNull(this)
|
||||
codegen.llvmFunctionOrNull(this)?.llvmValue
|
||||
return if (!isReifiedInline && functionLlvmValue != null) {
|
||||
context.debugInfo.subprograms.getOrPut(functionLlvmValue) {
|
||||
memScoped {
|
||||
val subroutineType = subroutineType(context, codegen.llvmTargetData)
|
||||
val llvmFunnction = codegen.llvmFunction(this@scope)
|
||||
diFunctionScope(name.asString(), llvmFunnction.name!!, startLine, subroutineType).also {
|
||||
val llvmFunction = codegen.llvmFunction(this@scope).llvmValue
|
||||
diFunctionScope(name.asString(), llvmFunction.name!!, startLine, subroutineType).also {
|
||||
if (!this@scope.isInline)
|
||||
DIFunctionAddSubprogram(llvmFunnction, it)
|
||||
DIFunctionAddSubprogram(llvmFunction, it)
|
||||
}
|
||||
}
|
||||
} as DIScopeOpaqueRef
|
||||
@@ -2374,7 +2375,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
private fun evaluateFileGlobalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
|
||||
val statePtr = getGlobalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction }
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
|
||||
|
||||
val bbInit = basicBlock("label_init", null)
|
||||
val bbExit = basicBlock("label_continue", null)
|
||||
@@ -2396,7 +2397,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
val globalStatePtr = getGlobalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val localState = getThreadLocalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val localStatePtr = localState.getAddress(functionGenerationContext)
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction }
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
|
||||
|
||||
val bbInit = basicBlock("label_init", null)
|
||||
val bbCheckLocalState = basicBlock("label_check_local", null)
|
||||
@@ -2422,7 +2423,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
private fun evaluateFileStandaloneThreadLocalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
|
||||
val state = getThreadLocalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val statePtr = state.getAddress(functionGenerationContext)
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction }
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
|
||||
|
||||
val bbInit = basicBlock("label_init", null)
|
||||
val bbExit = basicBlock("label_continue", null)
|
||||
@@ -2494,12 +2495,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
val annotation = irClass.annotations.findAnnotation(externalObjCClassFqName)!!
|
||||
val protocolGetterName = annotation.getAnnotationStringValue("protocolGetter")
|
||||
val protocolGetter = context.llvm.externalFunction(
|
||||
val protocolGetterProto = LlvmFunctionProto(
|
||||
protocolGetterName,
|
||||
functionType(int8TypePtr, false),
|
||||
irClass.llvmSymbolOrigin,
|
||||
LlvmRetType(int8TypePtr),
|
||||
origin = irClass.llvmSymbolOrigin,
|
||||
independent = true // Protocol is header-only declaration.
|
||||
)
|
||||
val protocolGetter = context.llvm.externalFunction(protocolGetterProto)
|
||||
|
||||
return call(protocolGetter, emptyList())
|
||||
}
|
||||
@@ -2571,20 +2573,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun callDirect(function: IrFunction, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime): LLVMValueRef {
|
||||
val llvmFunction = codegen.llvmFunction(function.target)
|
||||
return call(function, llvmFunction, args, resultLifetime)
|
||||
fun callDirect(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
|
||||
val functionDeclarations = codegen.llvmFunction(function.target)
|
||||
return call(function, functionDeclarations, args, resultLifetime)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun callVirtual(function: IrFunction, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime): LLVMValueRef {
|
||||
|
||||
val llvmFunction = functionGenerationContext.lookupVirtualImpl(args.first(), function)
|
||||
|
||||
return call(function, llvmFunction, args, resultLifetime) // Invoke the method
|
||||
fun callVirtual(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
|
||||
val functionDeclarations = functionGenerationContext.lookupVirtualImpl(args.first(), function)
|
||||
return call(function, functionDeclarations, args, resultLifetime)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -2602,7 +2600,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return result
|
||||
}
|
||||
|
||||
private fun call(function: IrFunction, llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
private fun call(function: IrFunction, llvmCallable: LlvmCallable, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime): LLVMValueRef {
|
||||
check(!function.isTypedIntrinsic)
|
||||
|
||||
@@ -2620,7 +2618,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
functionGenerationContext.switchThreadState(ThreadState.Native)
|
||||
}
|
||||
|
||||
val result = call(llvmFunction, args, resultLifetime, exceptionHandler)
|
||||
val result = call(llvmCallable, args, resultLifetime, exceptionHandler)
|
||||
|
||||
when {
|
||||
!function.isSuspend && function.returnType.isNothing() ->
|
||||
@@ -2629,16 +2627,18 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
functionGenerationContext.switchThreadState(ThreadState.Runnable)
|
||||
}
|
||||
|
||||
if (LLVMGetReturnType(getFunctionType(llvmFunction)) == voidType) {
|
||||
if (llvmCallable.returnType == voidType) {
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun call(function: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
exceptionHandler: ExceptionHandler = currentCodeContext.exceptionHandler): LLVMValueRef {
|
||||
private fun call(
|
||||
function: LlvmCallable, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
exceptionHandler: ExceptionHandler = currentCodeContext.exceptionHandler,
|
||||
): LLVMValueRef {
|
||||
return functionGenerationContext.call(function, args, resultLifetime, exceptionHandler)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -87,7 +87,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
|
||||
.distinctBy { it.selector }
|
||||
|
||||
allInitMethodsInfo.mapTo(this) {
|
||||
ObjCMethodDesc(it.selector, it.encoding, context.llvm.missingInitImp)
|
||||
ObjCMethodDesc(it.selector, it.encoding, context.llvm.missingInitImp.llvmValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
|
||||
ObjCMethodDesc(
|
||||
annotation.getAnnotationStringValue("selector"),
|
||||
annotation.getAnnotationStringValue("encoding"),
|
||||
it.llvmFunction
|
||||
it.llvmFunction.llvmValue
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+35
-21
@@ -48,27 +48,6 @@ private fun addTargetCpuAndFeaturesAttributes(context: Context, llvmFunction: LL
|
||||
}
|
||||
}
|
||||
|
||||
internal fun addLlvmAttributesForKotlinFunction(context: Context, irFunction: IrFunction, llvmFunction: LLVMValueRef) {
|
||||
if (irFunction.returnType.isNothing()) {
|
||||
setFunctionNoReturn(llvmFunction)
|
||||
}
|
||||
|
||||
if (mustNotInline(context, irFunction)) {
|
||||
setFunctionNoInline(llvmFunction)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mustNotInline(context: Context, irFunction: IrFunction): Boolean {
|
||||
if (context.shouldContainLocationDebugInfo()) {
|
||||
if (irFunction is IrConstructor && irFunction.isPrimary && irFunction.returnType.isThrowable()) {
|
||||
// To simplify skipping this constructor when scanning call stack in Kotlin_getCurrentStackTrace.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun shouldEnforceFramePointer(context: Context): Boolean {
|
||||
// TODO: do we still need it?
|
||||
if (!context.shouldOptimize()) {
|
||||
@@ -99,3 +78,38 @@ private fun enforceFramePointer(llvmFunction: LLVMValueRef, context: Context) {
|
||||
|
||||
LLVMAddTargetDependentFunctionAttr(llvmFunction, "frame-pointer", fpKind)
|
||||
}
|
||||
|
||||
interface LlvmAttribute {
|
||||
fun asAttributeKindId(): LLVMAttributeKindId
|
||||
}
|
||||
|
||||
// We use sealed class instead of enum because there are attributes with parameters
|
||||
// that we might want to use later. For example, align(<n>).
|
||||
sealed class LlvmParameterAttribute(private val llvmAttributeName: String) : LlvmAttribute {
|
||||
|
||||
override fun asAttributeKindId(): LLVMAttributeKindId = llvmAttributeKindIdCache.getOrPut(this) {
|
||||
getLlvmAttributeKindId(llvmAttributeName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val llvmAttributeKindIdCache = mutableMapOf<LlvmParameterAttribute, LLVMAttributeKindId>()
|
||||
}
|
||||
|
||||
object SignExt : LlvmParameterAttribute("signext")
|
||||
object ZeroExt : LlvmParameterAttribute("zeroext")
|
||||
}
|
||||
|
||||
sealed class LlvmFunctionAttribute(private val llvmAttributeName: String) : LlvmAttribute {
|
||||
|
||||
override fun asAttributeKindId(): LLVMAttributeKindId = llvmAttributeKindIdCache.getOrPut(this) {
|
||||
getLlvmAttributeKindId(llvmAttributeName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val llvmAttributeKindIdCache = mutableMapOf<LlvmFunctionAttribute, LLVMAttributeKindId>()
|
||||
}
|
||||
|
||||
object NoUnwind : LlvmFunctionAttribute("nounwind")
|
||||
object NoReturn : LlvmFunctionAttribute("noreturn")
|
||||
object NoInline : LlvmFunctionAttribute("noinline")
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import llvm.LLVMGetReturnType
|
||||
import llvm.LLVMTypeRef
|
||||
import llvm.LLVMValueRef
|
||||
|
||||
/**
|
||||
* Wrapper around LLVM value of functional type.
|
||||
*/
|
||||
class LlvmCallable(val llvmValue: LLVMValueRef, val attributeProvider: LlvmFunctionAttributeProvider) {
|
||||
val returnType: LLVMTypeRef by lazy {
|
||||
LLVMGetReturnType(functionType)!!
|
||||
}
|
||||
|
||||
val functionType: LLVMTypeRef by lazy {
|
||||
getFunctionType(llvmValue)
|
||||
}
|
||||
}
|
||||
+16
-17
@@ -34,8 +34,13 @@ enum class UniqueKind(val llvmName: String) {
|
||||
}
|
||||
|
||||
internal class LlvmDeclarations(private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) {
|
||||
fun forFunction(function: IrFunction) = forFunctionOrNull(function) ?: with(function){error("$name in $file/${parent.fqNameForIrSerialization}")}
|
||||
fun forFunctionOrNull(function: IrFunction) = (function.metadata as? CodegenFunctionMetadata)?.llvm
|
||||
fun forFunction(function: IrFunction): LlvmCallable =
|
||||
forFunctionOrNull(function) ?: with(function) {
|
||||
error("$name in $file/${parent.fqNameForIrSerialization}")
|
||||
}
|
||||
|
||||
fun forFunctionOrNull(function: IrFunction): LlvmCallable? =
|
||||
(function.metadata as? CodegenFunctionMetadata)?.llvm
|
||||
|
||||
fun forClass(irClass: IrClass) = (irClass.metadata as? CodegenClassMetadata)?.llvm ?:
|
||||
error(irClass.descriptor.toString())
|
||||
@@ -68,8 +73,6 @@ internal class KotlinObjCClassLlvmDeclarations(
|
||||
val bodyOffsetGlobal: StaticData.Global
|
||||
)
|
||||
|
||||
internal class FunctionLlvmDeclarations(val llvmFunction: LLVMValueRef)
|
||||
|
||||
internal class FieldLlvmDeclarations(val index: Int, val classBodyType: LLVMTypeRef)
|
||||
|
||||
internal class StaticFieldLlvmDeclarations(val storageAddressAccess: AddressAccess)
|
||||
@@ -338,8 +341,6 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
|
||||
if (!declaration.isReal) return
|
||||
|
||||
val llvmFunctionType = getLlvmFunctionType(declaration)
|
||||
|
||||
if ((declaration is IrConstructor && declaration.isObjCConstructor)) {
|
||||
return
|
||||
}
|
||||
@@ -351,11 +352,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
|| (declaration.isAccessor && declaration.isFromInteropLibrary())
|
||||
|| declaration.annotations.hasAnnotation(RuntimeNames.cCall)) return
|
||||
|
||||
context.llvm.externalFunction(declaration.computeSymbolName(), llvmFunctionType,
|
||||
// Assume that `external fun` is defined in native libs attached to this module:
|
||||
origin = declaration.llvmSymbolOrigin,
|
||||
independent = declaration.hasAnnotation(RuntimeNames.independent)
|
||||
)
|
||||
val proto = LlvmFunctionProto(declaration, declaration.computeSymbolName(), this)
|
||||
context.llvm.externalFunction(proto)
|
||||
} else {
|
||||
val symbolName = if (declaration.isExported()) {
|
||||
declaration.computeSymbolName().also {
|
||||
@@ -369,21 +367,22 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
} else {
|
||||
"kfun:" + qualifyInternalName(declaration)
|
||||
}
|
||||
|
||||
addLlvmFunctionWithDefaultAttributes(
|
||||
val proto = LlvmFunctionProto(declaration, symbolName, this)
|
||||
val llvmFunction = addLlvmFunctionWithDefaultAttributes(
|
||||
context,
|
||||
context.llvmModule!!,
|
||||
symbolName,
|
||||
llvmFunctionType
|
||||
proto.llvmFunctionType
|
||||
).also {
|
||||
addLlvmAttributesForKotlinFunction(context, declaration, it)
|
||||
proto.addFunctionAttributes(it)
|
||||
}
|
||||
LlvmCallable(llvmFunction, proto)
|
||||
}
|
||||
|
||||
declaration.metadata = CodegenFunctionMetadata(
|
||||
declaration.metadata?.name,
|
||||
declaration.konanLibrary,
|
||||
FunctionLlvmDeclarations(llvmFunction)
|
||||
llvmFunction
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -400,7 +399,7 @@ internal class CodegenClassMetadata(irClass: IrClass)
|
||||
private class CodegenFunctionMetadata(
|
||||
name: Name?,
|
||||
konanLibrary: KotlinLibrary?,
|
||||
val llvm: FunctionLlvmDeclarations
|
||||
val llvm: LlvmCallable
|
||||
) : KonanMetadata(name, konanLibrary), MetadataSource.Function
|
||||
|
||||
private class CodegenInstanceFieldMetadata(
|
||||
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.allocArray
|
||||
import kotlinx.cinterop.get
|
||||
import kotlinx.cinterop.memScoped
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.RuntimeNames
|
||||
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
||||
import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
import org.jetbrains.kotlin.ir.util.isThrowable
|
||||
|
||||
/**
|
||||
* Add attributes to LLVM function declaration and its invocation.
|
||||
*/
|
||||
interface LlvmFunctionAttributeProvider {
|
||||
fun addCallSiteAttributes(callSite: LLVMValueRef)
|
||||
|
||||
fun addFunctionAttributes(function: LLVMValueRef)
|
||||
|
||||
companion object {
|
||||
fun makeEmpty(): LlvmFunctionAttributeProvider =
|
||||
DummyLlvmFunctionAttributeProvider
|
||||
|
||||
fun copyFromExternal(externalFunction: LLVMValueRef): LlvmFunctionAttributeProvider =
|
||||
LlvmFunctionAttributesCopier(externalFunction)
|
||||
}
|
||||
}
|
||||
|
||||
private object DummyLlvmFunctionAttributeProvider : LlvmFunctionAttributeProvider {
|
||||
override fun addCallSiteAttributes(callSite: LLVMValueRef) {}
|
||||
|
||||
override fun addFunctionAttributes(function: LLVMValueRef) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies attributes from the given [externalFunction].
|
||||
* This is useful when the [externalFunction] is declared in the another LLVM module,
|
||||
* and we want to create an external declaration for it.
|
||||
*/
|
||||
private class LlvmFunctionAttributesCopier(private val externalFunction: LLVMValueRef) : LlvmFunctionAttributeProvider {
|
||||
|
||||
private val paramsCount: Int by lazy { LLVMCountParams(externalFunction) }
|
||||
|
||||
private val attributesForCallSite: List<List<LLVMAttributeRef>> by lazy {
|
||||
attributesForFunctionDeclaration.map {
|
||||
// We don't need attributes like correctly-rounded-divide-sqrt-fp-math or less-precise-fpmad at callsites.
|
||||
// So let's take only enum and integer attributes, should be enough to generate correct calls.
|
||||
it.filter {
|
||||
// This function is actually more like "is enum OR int attribute".
|
||||
LLVMIsEnumAttribute(it) != 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val attributesForFunctionDeclaration: List<List<LLVMAttributeRef>> by lazy {
|
||||
memScoped {
|
||||
val result = mutableListOf<List<LLVMAttributeRef>>()
|
||||
for (index in LLVMAttributeFunctionIndex..paramsCount) {
|
||||
val count = LLVMGetAttributeCountAtIndex(externalFunction, index)
|
||||
val attributesBuffer = allocArray<LLVMAttributeRefVar>(count)
|
||||
LLVMGetAttributesAtIndex(externalFunction, index, attributesBuffer)
|
||||
result += (0 until count).map { attributesBuffer[it]!! }
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
override fun addCallSiteAttributes(callSite: LLVMValueRef) {
|
||||
attributesForCallSite.withIndex().forEach { (listIndex, attributeList) ->
|
||||
attributeList.forEach { attributeRef ->
|
||||
LLVMAddCallSiteAttribute(callSite, LLVMAttributeFunctionIndex + listIndex, attributeRef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addFunctionAttributes(function: LLVMValueRef) {
|
||||
attributesForFunctionDeclaration.withIndex().forEach { (listIndex, attributeList) ->
|
||||
attributeList.forEach { attributeRef ->
|
||||
LLVMAddAttributeAtIndex(function, LLVMAttributeFunctionIndex + listIndex, attributeRef)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCallSiteAttributesAtIndex(context: LLVMContextRef, callSite: LLVMValueRef, index: Int, attributes: List<LlvmAttribute>) {
|
||||
attributes.forEach { attribute ->
|
||||
val llvmAttributeRef = createLlvmEnumAttribute(context, attribute.asAttributeKindId())
|
||||
LLVMAddCallSiteAttribute(callSite, index, llvmAttributeRef)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDeclarationAttributesAtIndex(context: LLVMContextRef, function: LLVMValueRef, index: Int, attributes: List<LlvmAttribute>) {
|
||||
attributes.forEach { attribute ->
|
||||
val llvmAttributeRef = createLlvmEnumAttribute(context, attribute.asAttributeKindId())
|
||||
LLVMAddAttributeAtIndex(function, index, llvmAttributeRef)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LLVM function's signature, enriched with attributes.
|
||||
*/
|
||||
internal open class LlvmFunctionSignature(
|
||||
val returnType: LlvmRetType,
|
||||
val parameterTypes: List<LlvmParamType> = emptyList(),
|
||||
val isVararg: Boolean = false,
|
||||
val functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
|
||||
) : LlvmFunctionAttributeProvider {
|
||||
|
||||
constructor(irFunction: IrFunction, contextUtils: ContextUtils) : this(
|
||||
returnType = contextUtils.getLlvmFunctionReturnType(irFunction),
|
||||
parameterTypes = contextUtils.getLlvmFunctionParameterTypes(irFunction),
|
||||
functionAttributes = inferFunctionAttributes(contextUtils, irFunction),
|
||||
isVararg = false,
|
||||
)
|
||||
|
||||
val llvmFunctionType by lazy {
|
||||
functionType(returnType.llvmType, isVararg, parameterTypes.map { it.llvmType })
|
||||
}
|
||||
|
||||
override fun addCallSiteAttributes(callSite: LLVMValueRef) {
|
||||
val caller = LLVMGetBasicBlockParent(LLVMGetInstructionParent(callSite))
|
||||
val llvmContext = LLVMGetModuleContext(LLVMGetGlobalParent(caller))!!
|
||||
addCallSiteAttributesAtIndex(llvmContext, callSite, LLVMAttributeFunctionIndex, functionAttributes)
|
||||
addCallSiteAttributesAtIndex(llvmContext, callSite, LLVMAttributeReturnIndex, returnType.attributes)
|
||||
repeat(parameterTypes.count()) {
|
||||
addCallSiteAttributesAtIndex(llvmContext, callSite, it + 1, parameterTypes[it].attributes)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addFunctionAttributes(function: LLVMValueRef) {
|
||||
val llvmContext = LLVMGetModuleContext(LLVMGetGlobalParent(function))!!
|
||||
addDeclarationAttributesAtIndex(llvmContext, function, LLVMAttributeFunctionIndex, functionAttributes)
|
||||
addDeclarationAttributesAtIndex(llvmContext, function, LLVMAttributeReturnIndex, returnType.attributes)
|
||||
repeat(parameterTypes.count()) {
|
||||
addDeclarationAttributesAtIndex(llvmContext, function, it + 1, parameterTypes[it].attributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prototype of a LLVM function that is not tied to a specific LLVM module.
|
||||
*/
|
||||
internal class LlvmFunctionProto(
|
||||
val name: String,
|
||||
returnType: LlvmRetType,
|
||||
parameterTypes: List<LlvmParamType> = emptyList(),
|
||||
functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
|
||||
val origin: CompiledKlibModuleOrigin,
|
||||
isVararg: Boolean = false,
|
||||
val independent: Boolean = false,
|
||||
) : LlvmFunctionSignature(returnType, parameterTypes, isVararg, functionAttributes) {
|
||||
constructor(
|
||||
name: String,
|
||||
signature: LlvmFunctionSignature,
|
||||
origin: CompiledKlibModuleOrigin,
|
||||
independent: Boolean = false,
|
||||
) : this(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, origin, signature.isVararg, independent)
|
||||
|
||||
constructor(irFunction: IrFunction, symbolName: String, contextUtils: ContextUtils) : this(
|
||||
name = symbolName,
|
||||
returnType = contextUtils.getLlvmFunctionReturnType(irFunction),
|
||||
parameterTypes = contextUtils.getLlvmFunctionParameterTypes(irFunction),
|
||||
functionAttributes = inferFunctionAttributes(contextUtils, irFunction),
|
||||
origin = irFunction.llvmSymbolOrigin,
|
||||
independent = irFunction.hasAnnotation(RuntimeNames.independent)
|
||||
)
|
||||
}
|
||||
|
||||
private fun mustNotInline(context: Context, irFunction: IrFunction): Boolean {
|
||||
if (context.shouldContainLocationDebugInfo()) {
|
||||
if (irFunction is IrConstructor && irFunction.isPrimary && irFunction.returnType.isThrowable()) {
|
||||
// To simplify skipping this constructor when scanning call stack in Kotlin_getCurrentStackTrace.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun inferFunctionAttributes(contextUtils: ContextUtils, irFunction: IrFunction): List<LlvmFunctionAttribute> =
|
||||
mutableListOf<LlvmFunctionAttribute>().apply {
|
||||
// suspend function can return value in case of COROUTINE_SUSPENDED.
|
||||
if (irFunction.returnType.isNothing() && !irFunction.isSuspend) {
|
||||
add(LlvmFunctionAttribute.NoReturn)
|
||||
}
|
||||
if (mustNotInline(contextUtils.context, irFunction)) {
|
||||
add(LlvmFunctionAttribute.NoInline)
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import llvm.LLVMTypeRef
|
||||
import org.jetbrains.kotlin.backend.common.ir.allParameters
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.unwrapToPrimitiveOrReference
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.classId
|
||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
|
||||
/**
|
||||
* LLVM function's parameter type with its attributes.
|
||||
*/
|
||||
class LlvmParamType(val llvmType: LLVMTypeRef, val attributes: List<LlvmParameterAttribute> = emptyList())
|
||||
|
||||
/**
|
||||
* A bit better readability for cases when [LlvmParamType] represents return type.
|
||||
*/
|
||||
typealias LlvmRetType = LlvmParamType
|
||||
|
||||
internal fun RuntimeAware.getLlvmFunctionParameterTypes(function: IrFunction): List<LlvmParamType> {
|
||||
val returnType = getLlvmFunctionReturnType(function).llvmType
|
||||
val paramTypes = ArrayList(function.allParameters.map { LlvmParamType(getLLVMType(it.type), defaultParameterAttributesForIrType(it.type)) })
|
||||
if (function.isSuspend)
|
||||
paramTypes.add(LlvmParamType(kObjHeaderPtr)) // Suspend functions have implicit parameter of type Continuation<>.
|
||||
if (isObjectType(returnType))
|
||||
paramTypes.add(LlvmParamType(kObjHeaderPtrPtr))
|
||||
|
||||
return paramTypes
|
||||
}
|
||||
|
||||
internal fun RuntimeAware.getLlvmFunctionReturnType(function: IrFunction): LlvmRetType {
|
||||
val returnType = when {
|
||||
function is IrConstructor -> LlvmParamType(voidType)
|
||||
function.isSuspend -> LlvmParamType(kObjHeaderPtr) // Suspend functions return Any?.
|
||||
else -> LlvmParamType(getLLVMReturnType(function.returnType), defaultParameterAttributesForIrType(function.returnType))
|
||||
}
|
||||
return returnType
|
||||
}
|
||||
|
||||
// Note: Probably, this function should become target-dependent in the future.
|
||||
private fun defaultParameterAttributesForIrType(irType: IrType): List<LlvmParameterAttribute> {
|
||||
// TODO: We perform type unwrapping twice: one to get the underlying type, and then this one.
|
||||
// Unwrapping is not cheap, so it might affect compilation time.
|
||||
return irType.unwrapToPrimitiveOrReference(
|
||||
eachInlinedClass = { inlinedClass, _ ->
|
||||
when (inlinedClass.classId) {
|
||||
UnsignedType.UBYTE.classId -> return listOf(LlvmParameterAttribute.ZeroExt)
|
||||
UnsignedType.USHORT.classId -> return listOf(LlvmParameterAttribute.ZeroExt)
|
||||
}
|
||||
},
|
||||
ifPrimitive = { primitiveType, _ ->
|
||||
when (primitiveType) {
|
||||
KonanPrimitiveType.BOOLEAN -> listOf(LlvmParameterAttribute.ZeroExt)
|
||||
KonanPrimitiveType.CHAR -> listOf(LlvmParameterAttribute.ZeroExt)
|
||||
KonanPrimitiveType.BYTE -> listOf(LlvmParameterAttribute.SignExt)
|
||||
KonanPrimitiveType.SHORT -> listOf(LlvmParameterAttribute.SignExt)
|
||||
KonanPrimitiveType.INT -> emptyList()
|
||||
KonanPrimitiveType.LONG -> emptyList()
|
||||
KonanPrimitiveType.FLOAT -> emptyList()
|
||||
KonanPrimitiveType.DOUBLE -> emptyList()
|
||||
KonanPrimitiveType.NON_NULL_NATIVE_PTR -> emptyList()
|
||||
KonanPrimitiveType.VECTOR128 -> emptyList()
|
||||
}
|
||||
},
|
||||
ifReference = {
|
||||
return listOf()
|
||||
},
|
||||
)
|
||||
}
|
||||
+1
-1
@@ -17,7 +17,7 @@ interface RuntimeAware {
|
||||
class Runtime(bitcodeFile: String) {
|
||||
val llvmModule: LLVMModuleRef = parseBitcodeFile(bitcodeFile)
|
||||
val calculatedLLVMTypes: MutableMap<IrType, LLVMTypeRef> = HashMap()
|
||||
val addedLLVMExternalFunctions: MutableMap<IrFunction, LLVMValueRef> = HashMap()
|
||||
val addedLLVMExternalFunctions: MutableMap<IrFunction, LlvmCallable> = HashMap()
|
||||
|
||||
internal fun getStructTypeOrNull(name: String) = LLVMGetTypeByName(llvmModule, "struct.$name")
|
||||
internal fun getStructType(name: String) = getStructTypeOrNull(name)
|
||||
|
||||
+2
-2
@@ -46,8 +46,8 @@ internal class LLVMCoverageInstrumentation(
|
||||
|
||||
// Each profiled function should have a global with its name in a specific format.
|
||||
private fun createFunctionNameGlobal(function: IrFunction): LLVMValueRef {
|
||||
val name = function.llvmFunction.name
|
||||
val pgoFunctionName = LLVMCreatePGOFunctionNameVar(function.llvmFunction, name)!!
|
||||
val name = function.llvmFunction.llvmValue.name
|
||||
val pgoFunctionName = LLVMCreatePGOFunctionNameVar(function.llvmFunction.llvmValue, name)!!
|
||||
return LLVMConstBitCast(pgoFunctionName, int8TypePtr)!!
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -54,7 +54,7 @@ internal class LLVMCoverageWriter(
|
||||
fileIds.toCValues(), fileIds.size.signExtend(),
|
||||
regions.toCValues(), regions.size.signExtend())
|
||||
|
||||
val functionName = context.llvmDeclarations.forFunction(functionRegions.function).llvmFunction.name
|
||||
val functionName = context.llvmDeclarations.forFunction(functionRegions.function).llvmValue.name
|
||||
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(context.llvmModule),
|
||||
functionName, functionRegions.structuralHash, functionCoverage)!!
|
||||
|
||||
|
||||
+37
-28
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.llvm.objc
|
||||
|
||||
import llvm.LLVMTypeRef
|
||||
import llvm.LLVMValueRef
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
|
||||
@@ -22,44 +21,54 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
|
||||
}
|
||||
|
||||
private val objcMsgSend = constPointer(
|
||||
context.llvm.externalFunction(
|
||||
context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"objc_msgSend",
|
||||
functionType(int8TypePtr, true, int8TypePtr, int8TypePtr),
|
||||
context.stdlibModule.llvmSymbolOrigin
|
||||
)
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)),
|
||||
isVararg = true,
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
)).llvmValue
|
||||
)
|
||||
|
||||
val objcRelease = context.llvm.externalFunction(
|
||||
"objc_release",
|
||||
functionType(voidType, false, int8TypePtr),
|
||||
context.stdlibModule.llvmSymbolOrigin
|
||||
)
|
||||
val objcRelease = run {
|
||||
val proto = LlvmFunctionProto(
|
||||
"objc_release",
|
||||
LlvmRetType(voidType),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
)
|
||||
context.llvm.externalFunction(proto)
|
||||
}
|
||||
|
||||
val objcAlloc = context.llvm.externalFunction(
|
||||
val objcAlloc = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"objc_alloc",
|
||||
functionType(int8TypePtr, false, int8TypePtr),
|
||||
context.stdlibModule.llvmSymbolOrigin
|
||||
)
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
))
|
||||
|
||||
val objcAutorelease = context.llvm.externalFunction(
|
||||
val objcAutorelease = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"llvm.objc.autorelease",
|
||||
functionType(int8TypePtr, false, int8TypePtr),
|
||||
context.stdlibModule.llvmSymbolOrigin
|
||||
).also {
|
||||
setFunctionNoUnwind(it)
|
||||
}
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
))
|
||||
|
||||
val objcAutoreleaseReturnValue = context.llvm.externalFunction(
|
||||
val objcAutoreleaseReturnValue = context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"llvm.objc.autoreleaseReturnValue",
|
||||
functionType(int8TypePtr, false, int8TypePtr),
|
||||
context.stdlibModule.llvmSymbolOrigin
|
||||
).also {
|
||||
setFunctionNoUnwind(it)
|
||||
}
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
origin = context.stdlibModule.llvmSymbolOrigin
|
||||
))
|
||||
|
||||
// TODO: this doesn't support stret.
|
||||
fun msgSender(functionType: LLVMTypeRef): LLVMValueRef =
|
||||
objcMsgSend.bitcast(pointerType(functionType)).llvm
|
||||
fun msgSender(functionType: LlvmFunctionSignature): LlvmCallable =
|
||||
LlvmCallable(
|
||||
objcMsgSend.bitcast(pointerType(functionType.llvmFunctionType)).llvm,
|
||||
functionType
|
||||
)
|
||||
}
|
||||
|
||||
internal fun FunctionGenerationContext.genObjCSelector(selector: String): LLVMValueRef {
|
||||
|
||||
+20
-20
@@ -31,7 +31,7 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||
}
|
||||
|
||||
val invokeImpl = functionGenerator(
|
||||
codegen.getLlvmFunctionType(invokeMethod),
|
||||
LlvmFunctionSignature(invokeMethod, codegen),
|
||||
"invokeFunction${bridge.nameSuffix}"
|
||||
).generate {
|
||||
val args = (0 until bridge.numberOfParameters).map { index ->
|
||||
@@ -69,9 +69,8 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||
bodyType,
|
||||
immutable = true
|
||||
)
|
||||
|
||||
return functionGenerator(
|
||||
functionType(codegen.kObjHeaderPtr, false, int8TypePtr, codegen.kObjHeaderPtrPtr),
|
||||
LlvmFunctionSignature(LlvmRetType(codegen.kObjHeaderPtr), listOf(LlvmParamType(int8TypePtr), LlvmParamType(codegen.kObjHeaderPtrPtr))),
|
||||
"convertBlock${bridge.nameSuffix}"
|
||||
).generate {
|
||||
val blockPtr = param(0)
|
||||
@@ -108,7 +107,7 @@ private fun FunctionGenerationContext.loadBlockInvoke(
|
||||
val blockLiteralType = codegen.runtime.getStructType("Block_literal_1")
|
||||
val invokePtr = structGep(bitcast(pointerType(blockLiteralType), blockPtr), 3)
|
||||
|
||||
return bitcast(pointerType(bridge.blockType.blockInvokeLlvmType), load(invokePtr))
|
||||
return bitcast(pointerType(bridge.blockType.blockInvokeLlvmType.llvmFunctionType), load(invokePtr))
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
|
||||
@@ -129,11 +128,10 @@ private val BlockPointerBridge.blockType: BlockType
|
||||
*/
|
||||
internal data class BlockType(val numberOfParameters: Int, val returnsVoid: Boolean)
|
||||
|
||||
private val BlockType.blockInvokeLlvmType: LLVMTypeRef
|
||||
get() = functionType(
|
||||
if (returnsVoid) voidType else int8TypePtr,
|
||||
false,
|
||||
(0..numberOfParameters).map { int8TypePtr }
|
||||
private val BlockType.blockInvokeLlvmType: LlvmFunctionSignature
|
||||
get() = LlvmFunctionSignature(
|
||||
LlvmRetType(if (returnsVoid) voidType else int8TypePtr),
|
||||
(0..numberOfParameters).map { LlvmParamType(int8TypePtr) }
|
||||
)
|
||||
|
||||
private val BlockPointerBridge.nameSuffix: String
|
||||
@@ -268,11 +266,8 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
||||
|
||||
val invokeMethod = context.ir.symbols.functionN(numberOfParameters).owner.simpleFunctions()
|
||||
.single { it.name == OperatorNameConventions.INVOKE }
|
||||
|
||||
val callee = lookupVirtualImpl(kotlinFunction, invokeMethod)
|
||||
|
||||
val result = callFromBridge(callee, listOf(kotlinFunction) + kotlinArguments, Lifetime.ARGUMENT)
|
||||
|
||||
val llvmDeclarations = lookupVirtualImpl(kotlinFunction, invokeMethod)
|
||||
val result = callFromBridge(llvmDeclarations, listOf(kotlinFunction) + kotlinArguments, Lifetime.ARGUMENT)
|
||||
if (bridge.returnsVoid) {
|
||||
ret(null)
|
||||
} else {
|
||||
@@ -293,7 +288,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
||||
)
|
||||
|
||||
return functionGenerator(
|
||||
functionType(int8TypePtr, false, codegen.kObjHeaderPtr),
|
||||
LlvmFunctionSignature(LlvmRetType(int8TypePtr), listOf(LlvmParamType(codegen.kObjHeaderPtr))),
|
||||
convertName
|
||||
).generate {
|
||||
val kotlinRef = param(0)
|
||||
@@ -335,8 +330,13 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
||||
}
|
||||
}
|
||||
|
||||
private val ObjCExportCodeGeneratorBase.retainBlock get() = context.llvm.externalFunction(
|
||||
"objc_retainBlock",
|
||||
functionType(int8TypePtr, false, int8TypePtr),
|
||||
CurrentKlibModuleOrigin
|
||||
)
|
||||
private val ObjCExportCodeGeneratorBase.retainBlock: LlvmCallable
|
||||
get() {
|
||||
val functionProto = LlvmFunctionProto(
|
||||
"objc_retainBlock",
|
||||
LlvmRetType(int8TypePtr),
|
||||
listOf(LlvmParamType(int8TypePtr)),
|
||||
origin = CurrentKlibModuleOrigin
|
||||
)
|
||||
return context.llvm.externalFunction(functionProto)
|
||||
}
|
||||
+84
-60
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.llvm.objcexport
|
||||
|
||||
import kotlinx.cinterop.toKString
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.allParameters
|
||||
import org.jetbrains.kotlin.backend.common.ir.allParametersCount
|
||||
@@ -86,19 +87,24 @@ internal class ObjCExportFunctionGenerationContext(
|
||||
}
|
||||
|
||||
internal class ObjCExportFunctionGenerationContextBuilder(
|
||||
functionType: LLVMTypeRef,
|
||||
functionType: LlvmFunctionSignature,
|
||||
functionName: String,
|
||||
val objCExportCodegen: ObjCExportCodeGeneratorBase
|
||||
) : FunctionGenerationContextBuilder<ObjCExportFunctionGenerationContext>(
|
||||
functionType,
|
||||
functionType.llvmFunctionType,
|
||||
functionName,
|
||||
objCExportCodegen.codegen
|
||||
) {
|
||||
// Not a very pleasant way to provide attributes to the generated function.
|
||||
init {
|
||||
functionType.addFunctionAttributes(function)
|
||||
}
|
||||
|
||||
override fun build() = ObjCExportFunctionGenerationContext(this)
|
||||
}
|
||||
|
||||
internal inline fun ObjCExportCodeGeneratorBase.functionGenerator(
|
||||
functionType: LLVMTypeRef,
|
||||
functionType: LlvmFunctionSignature,
|
||||
functionName: String,
|
||||
configure: ObjCExportFunctionGenerationContextBuilder.() -> Unit = {}
|
||||
): ObjCExportFunctionGenerationContextBuilder = ObjCExportFunctionGenerationContextBuilder(
|
||||
@@ -114,29 +120,42 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
|
||||
|
||||
val rttiGenerator = RTTIGenerator(context)
|
||||
|
||||
private val objcTerminate: LLVMValueRef by lazy {
|
||||
context.llvm.externalFunction(
|
||||
private val objcTerminate: LlvmCallable by lazy {
|
||||
context.llvm.externalFunction(LlvmFunctionProto(
|
||||
"objc_terminate",
|
||||
functionType(voidType, false),
|
||||
CurrentKlibModuleOrigin
|
||||
).also {
|
||||
setFunctionNoUnwind(it)
|
||||
}
|
||||
LlvmRetType(voidType),
|
||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||
origin = CurrentKlibModuleOrigin
|
||||
))
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
rttiGenerator.dispose()
|
||||
}
|
||||
|
||||
fun FunctionGenerationContext.callFromBridge(
|
||||
llvmFunction: LLVMValueRef,
|
||||
args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
toNative: Boolean = false,
|
||||
): LLVMValueRef {
|
||||
val llvmDeclarations = LlvmCallable(
|
||||
llvmFunction,
|
||||
// llvmFunction could be a function pointer here, and we can't infer attributes from it.
|
||||
LlvmFunctionAttributeProvider.makeEmpty()
|
||||
)
|
||||
return callFromBridge(llvmDeclarations, args, resultLifetime, toNative)
|
||||
}
|
||||
|
||||
// TODO: currently bridges don't have any custom `landingpad`s,
|
||||
// so it is correct to use [callAtFunctionScope] here.
|
||||
// However, exception handling probably should be refactored
|
||||
// (e.g. moved from `IrToBitcode.kt` to [FunctionGenerationContext]).
|
||||
fun FunctionGenerationContext.callFromBridge(
|
||||
function: LLVMValueRef,
|
||||
function: LlvmCallable,
|
||||
args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
toNative: Boolean = false
|
||||
toNative: Boolean = false,
|
||||
): LLVMValueRef {
|
||||
|
||||
// TODO: it is required only for Kotlin-to-Objective-C bridges.
|
||||
@@ -220,19 +239,18 @@ internal class ObjCExportCodeGenerator(
|
||||
}
|
||||
|
||||
fun FunctionGenerationContext.genSendMessage(
|
||||
returnType: LLVMTypeRef,
|
||||
returnType: LlvmParamType,
|
||||
parameterTypes: List<LlvmParamType>,
|
||||
receiver: LLVMValueRef,
|
||||
selector: String,
|
||||
switchToNative: Boolean,
|
||||
vararg args: LLVMValueRef,
|
||||
): LLVMValueRef {
|
||||
|
||||
val objcMsgSendType = functionType(
|
||||
val objcMsgSendType = LlvmFunctionSignature(
|
||||
returnType,
|
||||
false,
|
||||
listOf(int8TypePtr, int8TypePtr) + args.map { it.type }
|
||||
listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)) + parameterTypes
|
||||
)
|
||||
|
||||
return callFromBridge(msgSender(objcMsgSendType), listOf(receiver, genSelector(selector)) + args, toNative = switchToNative)
|
||||
}
|
||||
|
||||
@@ -662,7 +680,11 @@ private fun ObjCExportCodeGeneratorBase.buildWritableTypeInfoValue(
|
||||
typeAdapter: ConstPointer? = null
|
||||
): Struct {
|
||||
if (convertToRetained != null) {
|
||||
assert(convertToRetained.llvmType == pointerType(functionType(int8TypePtr, false, codegen.kObjHeaderPtr)))
|
||||
val expectedType = pointerType(functionType(int8TypePtr, false, codegen.kObjHeaderPtr))
|
||||
assert(convertToRetained.llvmType == expectedType) {
|
||||
"Expected: ${LLVMPrintTypeToString(expectedType)!!.toKString()} " +
|
||||
"found: ${LLVMPrintTypeToString(convertToRetained.llvmType)!!.toKString()}"
|
||||
}
|
||||
}
|
||||
|
||||
val objCExportAddition = Struct(runtime.typeInfoObjCExportAddition,
|
||||
@@ -675,8 +697,8 @@ private fun ObjCExportCodeGeneratorBase.buildWritableTypeInfoValue(
|
||||
return Struct(writableTypeInfoType, objCExportAddition)
|
||||
}
|
||||
|
||||
private val ObjCExportCodeGenerator.kotlinToObjCFunctionType: LLVMTypeRef
|
||||
get() = functionType(int8TypePtr, false, codegen.kObjHeaderPtr)
|
||||
private val ObjCExportCodeGenerator.kotlinToObjCFunctionType: LlvmFunctionSignature
|
||||
get() = LlvmFunctionSignature(LlvmRetType(int8TypePtr), listOf(LlvmParamType(codegen.kObjHeaderPtr)), isVararg = false)
|
||||
|
||||
private val ObjCExportCodeGeneratorBase.objCToKotlinFunctionType: LLVMTypeRef
|
||||
get() = functionType(codegen.kObjHeaderPtr, false, int8TypePtr, codegen.kObjHeaderPtrPtr)
|
||||
@@ -714,11 +736,14 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(
|
||||
)
|
||||
|
||||
val value = kotlinToObjC(kotlinValue, objCValueType)
|
||||
|
||||
val valueParameterTypes: List<LlvmParamType> = listOf(
|
||||
LlvmParamType(value.type, objCValueType.defaultParameterAttributes)
|
||||
)
|
||||
val nsNumberSubclass = genGetLinkedClass(namer.numberBoxName(boxClass.classId!!).binaryName)
|
||||
val switchToNative = false // We consider these methods fast enough.
|
||||
val instance = callFromBridge(objcAlloc, listOf(nsNumberSubclass), toNative = switchToNative)
|
||||
ret(genSendMessage(int8TypePtr, instance, nsNumberInitSelector, switchToNative, value))
|
||||
val returnType = LlvmRetType(int8TypePtr)
|
||||
ret(genSendMessage(returnType, valueParameterTypes, instance, nsNumberInitSelector, switchToNative, value))
|
||||
}
|
||||
|
||||
LLVMSetLinkage(converter, LLVMLinkage.LLVMPrivateLinkage)
|
||||
@@ -782,7 +807,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
||||
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
||||
setObjCExportTypeInfo(
|
||||
symbols.string.owner,
|
||||
constPointer(context.llvm.Kotlin_ObjCExport_CreateRetainedNSStringFromKString)
|
||||
constPointer(context.llvm.Kotlin_ObjCExport_CreateRetainedNSStringFromKString.llvmValue)
|
||||
)
|
||||
|
||||
emitCollectionConverters()
|
||||
@@ -792,11 +817,11 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
||||
|
||||
private fun ObjCExportCodeGenerator.emitCollectionConverters() {
|
||||
|
||||
fun importConverter(name: String): ConstPointer = constPointer(context.llvm.externalFunction(
|
||||
fun importConverter(name: String): ConstPointer = constPointer(context.llvm.externalFunction(LlvmFunctionProto(
|
||||
name,
|
||||
kotlinToObjCFunctionType,
|
||||
CurrentKlibModuleOrigin
|
||||
))
|
||||
origin = CurrentKlibModuleOrigin
|
||||
)).llvmValue)
|
||||
|
||||
setObjCExportTypeInfo(
|
||||
symbols.list.owner,
|
||||
@@ -840,7 +865,8 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
|
||||
debugInfo: Boolean = false,
|
||||
genBody: ObjCExportFunctionGenerationContext.() -> Unit
|
||||
): LLVMValueRef {
|
||||
val result = functionGenerator(objCFunctionType(context, methodBridge), "objc2kotlin") {
|
||||
val functionType = objCFunctionType(context, methodBridge)
|
||||
val result = functionGenerator(functionType, "objc2kotlin") {
|
||||
if (debugInfo) {
|
||||
this.setupBridgeDebugInfo()
|
||||
}
|
||||
@@ -882,13 +908,12 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||
listOf(param(0), codegen.typeInfoValue(target.parent as IrClass))
|
||||
)
|
||||
}
|
||||
val llvmTarget = if (!isVirtual) {
|
||||
val llvmCallable = if (!isVirtual) {
|
||||
codegen.llvmFunction(target)
|
||||
} else {
|
||||
lookupVirtualImpl(args.first(), target)
|
||||
}
|
||||
|
||||
call(llvmTarget, args, resultLifetime, exceptionHandler)
|
||||
call(llvmCallable, args, resultLifetime, exceptionHandler)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,7 +992,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
|
||||
// Release init receiver, as required by convention.
|
||||
callFromBridge(objcRelease, listOf(param(0)), toNative = true)
|
||||
}
|
||||
Zero(returnType.objCType(context)).llvm
|
||||
Zero(returnType.toLlvmRetType(context).llvmType).llvm
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1104,7 +1129,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
|
||||
val objcMsgSend = msgSender(objCFunctionType(context, methodBridge))
|
||||
|
||||
val functionType = codegen.getLlvmFunctionType(irFunction)
|
||||
val functionType = LlvmFunctionSignature(irFunction, codegen)
|
||||
|
||||
val result = functionGenerator(functionType, "kotlin2objc").generate {
|
||||
var errorOutPtr: LLVMValueRef? = null
|
||||
@@ -1614,7 +1639,8 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
||||
MethodBridgeReceiver.Static, valueParameters = emptyList()
|
||||
)
|
||||
|
||||
val imp = functionGenerator(objCFunctionType(context, methodBridge), "objc2kotlin") {
|
||||
val functionType = objCFunctionType(context, methodBridge)
|
||||
val imp = functionGenerator(functionType, "objc2kotlin") {
|
||||
switchToRunnable = true
|
||||
}.generate {
|
||||
block()
|
||||
@@ -1700,12 +1726,10 @@ private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportC
|
||||
return objCToKotlinMethodAdapter(selector, methodBridge, imp)
|
||||
}
|
||||
|
||||
private fun objCFunctionType(context: Context, methodBridge: MethodBridge): LLVMTypeRef {
|
||||
val paramTypes = methodBridge.paramBridges.map { it.objCType }
|
||||
|
||||
val returnType = methodBridge.returnBridge.objCType(context)
|
||||
|
||||
return functionType(returnType, false, *(paramTypes.toTypedArray()))
|
||||
private fun objCFunctionType(context: Context, methodBridge: MethodBridge): LlvmFunctionSignature {
|
||||
val paramTypes = methodBridge.paramBridges.map { it.toLlvmParamType() }
|
||||
val returnType = methodBridge.returnBridge.toLlvmRetType(context)
|
||||
return LlvmFunctionSignature(returnType, paramTypes, isVararg = false)
|
||||
}
|
||||
|
||||
private val ObjCValueType.llvmType: LLVMTypeRef get() = when (this) {
|
||||
@@ -1724,31 +1748,31 @@ private val ObjCValueType.llvmType: LLVMTypeRef get() = when (this) {
|
||||
ObjCValueType.POINTER -> kInt8Ptr
|
||||
}
|
||||
|
||||
private val MethodBridgeParameter.objCType: LLVMTypeRef get() = when (this) {
|
||||
is MethodBridgeValueParameter.Mapped -> this.bridge.objCType
|
||||
is MethodBridgeReceiver -> ReferenceBridge.objCType
|
||||
MethodBridgeSelector -> int8TypePtr
|
||||
MethodBridgeValueParameter.ErrorOutParameter -> pointerType(ReferenceBridge.objCType)
|
||||
MethodBridgeValueParameter.SuspendCompletion -> int8TypePtr
|
||||
private fun MethodBridgeParameter.toLlvmParamType(): LlvmParamType = when (this) {
|
||||
is MethodBridgeValueParameter.Mapped -> this.bridge.toLlvmParamType()
|
||||
is MethodBridgeReceiver -> ReferenceBridge.toLlvmParamType()
|
||||
MethodBridgeSelector -> LlvmParamType(int8TypePtr)
|
||||
MethodBridgeValueParameter.ErrorOutParameter -> LlvmParamType(pointerType(ReferenceBridge.toLlvmParamType().llvmType))
|
||||
MethodBridgeValueParameter.SuspendCompletion -> LlvmParamType(int8TypePtr)
|
||||
}
|
||||
|
||||
private fun MethodBridge.ReturnValue.objCType(context: Context): LLVMTypeRef {
|
||||
return when (this) {
|
||||
MethodBridge.ReturnValue.Suspend,
|
||||
MethodBridge.ReturnValue.Void -> voidType
|
||||
MethodBridge.ReturnValue.HashCode -> if (context.is64BitNSInteger()) int64Type else int32Type
|
||||
is MethodBridge.ReturnValue.Mapped -> this.bridge.objCType
|
||||
MethodBridge.ReturnValue.WithError.Success -> ObjCValueType.BOOL.llvmType
|
||||
private fun MethodBridge.ReturnValue.toLlvmRetType(
|
||||
context: Context
|
||||
): LlvmRetType = when (this) {
|
||||
MethodBridge.ReturnValue.Suspend,
|
||||
MethodBridge.ReturnValue.Void -> LlvmRetType(voidType)
|
||||
MethodBridge.ReturnValue.HashCode -> LlvmRetType(if (context.is64BitNSInteger()) int64Type else int32Type)
|
||||
is MethodBridge.ReturnValue.Mapped -> this.bridge.toLlvmParamType()
|
||||
MethodBridge.ReturnValue.WithError.Success -> ValueTypeBridge(ObjCValueType.BOOL).toLlvmParamType()
|
||||
|
||||
MethodBridge.ReturnValue.Instance.InitResult,
|
||||
MethodBridge.ReturnValue.Instance.FactoryResult -> ReferenceBridge.objCType
|
||||
is MethodBridge.ReturnValue.WithError.ZeroForError -> this.successBridge.objCType(context)
|
||||
}
|
||||
MethodBridge.ReturnValue.Instance.InitResult,
|
||||
MethodBridge.ReturnValue.Instance.FactoryResult -> ReferenceBridge.toLlvmParamType()
|
||||
is MethodBridge.ReturnValue.WithError.ZeroForError -> this.successBridge.toLlvmRetType(context)
|
||||
}
|
||||
|
||||
private val TypeBridge.objCType: LLVMTypeRef get() = when (this) {
|
||||
is ReferenceBridge, is BlockPointerBridge -> int8TypePtr
|
||||
is ValueTypeBridge -> this.objCValueType.llvmType
|
||||
private fun TypeBridge.toLlvmParamType(): LlvmParamType = when (this) {
|
||||
is ReferenceBridge, is BlockPointerBridge -> LlvmParamType(int8TypePtr)
|
||||
is ValueTypeBridge -> LlvmParamType(this.objCValueType.llvmType, this.objCValueType.defaultParameterAttributes)
|
||||
}
|
||||
|
||||
internal fun ObjCExportCodeGenerator.getEncoding(methodBridge: MethodBridge): String {
|
||||
@@ -1758,7 +1782,7 @@ internal fun ObjCExportCodeGenerator.getEncoding(methodBridge: MethodBridge): St
|
||||
methodBridge.paramBridges.forEach {
|
||||
append(it.objCEncoding)
|
||||
append(paramOffset)
|
||||
paramOffset += LLVMStoreSizeOfType(runtime.targetData, it.objCType).toInt()
|
||||
paramOffset += LLVMStoreSizeOfType(runtime.targetData, it.toLlvmParamType().llvmType).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-7
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.LlvmParameterAttribute
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -153,15 +154,16 @@ object ObjCVoidType : ObjCType() {
|
||||
override fun render(attrsAndName: String) = "void".withAttrsAndName(attrsAndName)
|
||||
}
|
||||
|
||||
internal enum class ObjCValueType(val encoding: String) {
|
||||
BOOL("c"),
|
||||
UNICHAR("S"),
|
||||
CHAR("c"),
|
||||
SHORT("s"),
|
||||
internal enum class ObjCValueType(val encoding: String, val defaultParameterAttributes: List<LlvmParameterAttribute> = emptyList()) {
|
||||
BOOL("c", listOf(LlvmParameterAttribute.SignExt)),
|
||||
UNICHAR("S", listOf(LlvmParameterAttribute.ZeroExt)),
|
||||
// TODO: Switch to explicit SIGNED_CHAR
|
||||
CHAR("c", listOf(LlvmParameterAttribute.SignExt)),
|
||||
SHORT("s", listOf(LlvmParameterAttribute.SignExt)),
|
||||
INT("i"),
|
||||
LONG_LONG("q"),
|
||||
UNSIGNED_CHAR("C"),
|
||||
UNSIGNED_SHORT("S"),
|
||||
UNSIGNED_CHAR("C", listOf(LlvmParameterAttribute.ZeroExt)),
|
||||
UNSIGNED_SHORT("S", listOf(LlvmParameterAttribute.ZeroExt)),
|
||||
UNSIGNED_INT("I"),
|
||||
UNSIGNED_LONG_LONG("Q"),
|
||||
FLOAT("f"),
|
||||
|
||||
Reference in New Issue
Block a user