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 c1661a67cbc..ee3fc0e3c11 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 @@ -138,15 +138,19 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { fun load(value:LLVMOpaqueValue, varName: String):LLVMOpaqueValue = LLVMBuildLoad(context.llvmBuilder, value, varName)!! fun store(value:LLVMOpaqueValue, ptr:LLVMOpaqueValue):LLVMOpaqueValue = LLVMBuildStore(context.llvmBuilder, value, ptr)!! - fun call(descriptor: FunctionDescriptor, args: MutableList, result: String?): LLVMOpaqueValue? { - if (args.size == 0) return LLVMBuildCall(context.llvmBuilder, descriptor.llvmFunction.getLlvmValue(), null, 0, result) + //-------------------------------------------------------------------------// + + fun call(llvmFunction: LLVMOpaqueValue?, args: MutableList, result: String?): LLVMOpaqueValue? { + if (args.size == 0) return LLVMBuildCall(context.llvmBuilder, llvmFunction, null, 0, result) memScoped { val rargs = alloc(array[args.size](Ref to LLVMOpaqueValue)) - args.forEachIndexed { i, llvmOpaqueValue -> rargs[i].value = args[i]} - return LLVMBuildCall(context.llvmBuilder, descriptor.llvmFunction.getLlvmValue(), rargs[0], args.size, result) - } + args.forEachIndexed { i, llvmOpaqueValue -> rargs[i].value = args[i] } + return LLVMBuildCall(context.llvmBuilder, llvmFunction, rargs[0], args.size, result) + } } + //-------------------------------------------------------------------------// + fun trap() { // LLVM doesn't seem to provide API to get intrinsics; // workaround this by declaring the intrinsic explicitly: @@ -165,16 +169,6 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { fun typeInfoType(descriptor: ClassDescriptor): LLVMOpaqueType? = descriptor.llvmTypeInfoPtr.getLlvmType() fun typeInfoValue(descriptor: ClassDescriptor): LLVMOpaqueValue? = descriptor.llvmTypeInfoPtr.getLlvmValue() - fun superCall(result:String, descriptor:ClassConstructorDescriptor, args:MutableList ):LLVMOpaqueValue? { - val tmp = load(thisVariable(), tmpVariable()) - var rargs:MutableList? = null - if (args.size != 0) - rargs = mutableListOf(tmp, *args.toTypedArray()) - else - rargs = mutableListOf(tmp) - return call(descriptor, rargs, result) - } - fun thisVariable() = variable("this")!! fun param(fn: FunctionDescriptor?, i: Int): LLVMOpaqueValue? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i) @@ -182,6 +176,10 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { fun basicBlock(): LLVMOpaqueBasicBlock? = LLVMAppendBasicBlock(currentFunction!!.llvmFunction.getLlvmValue(), currentFunction!!.bbLabel()) fun lastBasicBlock(): LLVMOpaqueBasicBlock? = LLVMGetLastBasicBlock(currentFunction!!.llvmFunction.getLlvmValue()) + + fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction.getLlvmValue() + fun functionHash(descriptor: FunctionDescriptor): LLVMOpaqueValue? = descriptor.functionName.localHash.getLlvmValue() + } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt index 06027b44d83..dcad7bbbd1e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt @@ -26,6 +26,8 @@ internal class Context(val irModule: IrModuleFragment, val runtime: Runtime, val val allocInstanceFunction = importRtFunction("AllocInstance") val allocArrayFunction = importRtFunction("AllocArrayInstance") + val lookupFieldOffset = importRtFunction("LookupFieldOffset") + val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod") fun dispose() { LLVMDisposeBuilder(llvmBuilder) 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 f27f710063f..9b09bdb0d70 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 @@ -276,7 +276,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid when { value.descriptor is FunctionDescriptor -> return evaluateFunctionCall(tmpVariableName, value as IrCall, args) - value is IrDelegatingConstructorCall -> return generator.superCall(tmpVariableName, value.descriptor, args) + value is IrDelegatingConstructorCall -> return superCall(tmpVariableName, value.descriptor, args) else -> { TODO() } @@ -388,7 +388,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateSimpleFunctionCall(tmpVariableName: String, descriptor: FunctionDescriptor, args: MutableList): LLVMOpaqueValue? { //logger.log("evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}") - return generator.call(descriptor, args, tmpVariableName) + if (descriptor.isOverridable) + return callVirtual(descriptor, args, tmpVariableName) + else + return callDirect(descriptor, args, tmpVariableName) } //-------------------------------------------------------------------------// @@ -483,4 +486,49 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid branch.condition is IrConst<*> // If branch condition is constant. && (branch.condition as IrConst<*>).value as Boolean // If condition is "true" + //-------------------------------------------------------------------------// + + fun callDirect(descriptor: FunctionDescriptor, args: MutableList, result: String?): LLVMOpaqueValue? { + val llvmFunction = generator.functionLlvmValue(descriptor) + return generator.call(llvmFunction, args, result) + } + + //-------------------------------------------------------------------------// + + /* Runtime constant */ + private val kTypeInfo = LLVMGetTypeByName(context.llvmModule, "struct.TypeInfo")!! + private val kTypeInfoPtr = pointerType(kTypeInfo) + private val kInt8Ptr = pointerType(LLVMInt8Type()) + private val kInt8PtrPtr = pointerType(kInt8Ptr) + + //-------------------------------------------------------------------------// + + fun callVirtual(descriptor: FunctionDescriptor, args: MutableList, result: String?): LLVMOpaqueValue? { + val thisI8PtrPtr = generator.bitcast(kInt8PtrPtr, args[0]!!, generator.tmpVariable()) // Cast "this (i8*)" to i8**. + val typeInfoI8Ptr = generator.load(thisI8PtrPtr!!, generator.tmpVariable()) // Load TypeInfo address. + val typeInfoPtr = generator.bitcast(kTypeInfoPtr, typeInfoI8Ptr, generator.tmpVariable()) // Cast TypeInfo (i8*) to TypeInfo*. + val methodHash = generator.functionHash(descriptor) // Calculate hash of the method to be invoked + val lookupArgs = mutableListOf(typeInfoPtr, methodHash) // Prepare args for lookup + val llvmMethod = generator.call( + context.lookupOpenMethodFunction, + lookupArgs, + generator.tmpVariable()) // Get method ptr to be invoked + + val functionPtrType = pointerType(getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked + val function = generator.bitcast(functionPtrType, llvmMethod!!, generator.tmpVariable()) // Cast method address to the type + return generator.call(function, args, result) // Invoke the method + } + + //-------------------------------------------------------------------------// + + fun superCall(result:String, descriptor:ClassConstructorDescriptor, args:MutableList ):LLVMOpaqueValue? { + val tmp = generator.load(generator.thisVariable(), generator.tmpVariable()) + var rargs:MutableList? = null + if (args.size != 0) + rargs = mutableListOf(tmp, *args.toTypedArray()) + else + rargs = mutableListOf(tmp) + return callDirect(descriptor, rargs, result) + } + }