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