From b5ffc48547871125e618d7144349c11d15a75eb0 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Thu, 8 Dec 2016 15:01:32 +0700 Subject: [PATCH] backend.konan: support function types in codegen --- .../backend/konan/llvm/CodeGenerator.kt | 1 + .../kotlin/backend/konan/llvm/DataLayout.kt | 2 + .../kotlin/backend/konan/llvm/IrToBitcode.kt | 42 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 9e3acbc0033..93060642616 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -154,6 +154,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun lastBasicBlock(): LLVMBasicBlockRef? = LLVMGetLastBasicBlock(currentFunction!!.llvmFunction) fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction + fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm fun br(bbLabel: LLVMBasicBlockRef): LLVMValueRef { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt index 3417e696bee..19f29e305a9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt @@ -1,6 +1,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import llvm.* +import org.jetbrains.kotlin.backend.konan.isUnboundCallableReference import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.types.KotlinType @@ -8,6 +9,7 @@ internal fun ContextUtils.getLLVMType(type: KotlinType): LLVMTypeRef { return when { // Nullable types must be represented as objects for boxing. type.isMarkedNullable -> this.kObjHeaderPtr + type.isUnboundCallableReference() -> int8TypePtr KotlinBuiltIns.isBoolean(type) -> LLVMInt1Type() KotlinBuiltIns.isByte(type) -> LLVMInt8Type() KotlinBuiltIns.isShort(type) || KotlinBuiltIns.isChar(type) -> LLVMInt16Type() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index fb456d09b56..ba7f0d0d70b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -4,6 +4,7 @@ import kotlinx.cinterop.* import llvm.* import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrElement @@ -607,12 +608,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid is IrTry -> return evaluateTry ( value) is IrStringConcatenation -> return evaluateStringConcatenation(tmpVariableName, value) is IrBlockBody -> return evaluateBlock (tmpVariableName, value as IrStatementContainer) + is IrComposite -> return evaluateBlock (tmpVariableName, value) is IrWhileLoop -> return evaluateWhileLoop ( value) is IrDoWhileLoop -> return evaluateDoWhileLoop ( value) is IrVararg -> return evaluateVararg (tmpVariableName, value) is IrBreak -> return evaluateBreak ( value) is IrContinue -> return evaluateContinue ( value) is IrGetObjectValue -> return evaluateGetObjectValue (tmpVariableName, value) + is IrCallableReference -> return evaluateCallableReference (tmpVariableName, value) null -> return null else -> { TODO("${ir2string(value)}") @@ -1549,9 +1552,19 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// + private fun evaluateCallableReference(tmpVariableName: String, expression: IrCallableReference): LLVMValueRef { + assert (expression.type.isUnboundCallableReference()) + assert (expression.getArguments().isEmpty()) + val entry = codegen.functionEntryPointAddress(expression.descriptor as FunctionDescriptor) + return entry + } + + //-------------------------------------------------------------------------// + private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: List): LLVMValueRef { val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor when (descriptor) { + is FunctionInvokeDescriptor -> return evaluateFunctionInvoke (tmpVariableName, descriptor, args) is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (tmpVariableName, callee, args) is ClassConstructorDescriptor -> return evaluateConstructorCall (tmpVariableName, callee, args) else -> return evaluateSimpleFunctionCall(tmpVariableName, descriptor, args) @@ -1560,6 +1573,35 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// + private val functionImplUnboundRefGetter by lazy { + context.builtIns.getKonanInternalClass("FunctionImpl") + .unsubstitutedMemberScope.getContributedDescriptors() + .filterIsInstance() + .single { it.name.asString() == "unboundRef" } + .getter!! + } + + private fun evaluateFunctionInvoke(tmpVariableName: String, + descriptor: FunctionInvokeDescriptor, + args: List): LLVMValueRef { + + // Note: the whole function code below is written in the assumption that + // `invoke` method receiver is passed as first argument. + + val functionImpl = args[0] + + val unboundRefType = codegen.getLlvmFunctionType(descriptor) + + val unboundRef = evaluateSimpleFunctionCall(codegen.newVar(), + functionImplUnboundRefGetter, listOf(functionImpl)) + + val entryPtr = codegen.bitcast(pointerType(unboundRefType), unboundRef, "entry") + + return call(descriptor, entryPtr, args, tmpVariableName) + } + + //-------------------------------------------------------------------------// + private fun evaluateSimpleFunctionCall(tmpVariableName: String, descriptor: FunctionDescriptor, args: List): LLVMValueRef { //logger.log("evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}") if (descriptor.isOverridable)