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