backend: implement try-catch-finally

also add some hacks to handle unreachable code
This commit is contained in:
Svyatoslav Scherbina
2016-11-28 18:20:17 +07:00
parent e2dbeae85e
commit 9848091186
5 changed files with 764 additions and 181 deletions
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.types.KotlinType
internal class CodeGenerator(override val context:Context) : ContextUtils {
internal class CodeGenerator(override val context: Context) : ContextUtils {
var currentFunction:FunctionDescriptor? = null
fun function(declaration: IrFunction) {
@@ -47,11 +47,10 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
private fun prolog(declaration: IrFunction): LLVMValueRef? {
variableIndex = 0
labelIndex = 0
currentFunction = declaration.descriptor
val fn = declaration.descriptor.llvmFunction.getLlvmValue()
val block = LLVMAppendBasicBlock(fn, "entry")
LLVMPositionBuilderAtEnd(context.llvmBuilder, block)
val block = LLVMAppendBasicBlock(fn, "entry")!!
positionAtEnd(block)
function2variables.put(declaration.descriptor, mutableMapOf())
return fn
}
@@ -66,13 +65,7 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
get() = variableIndex
set(i:Int) { variableIndex = i}
private var labelIndex:Int = 0
private var FunctionDescriptor.bbLabelIndex: Int
get() = labelIndex
set(i:Int) { labelIndex = i}
fun FunctionDescriptor.tmpVariable():String = "tmp_${tmpVariableIndex++}"
fun FunctionDescriptor.bbLabel():String = "label_${bbLabelIndex++}"
fun registerVariable(varName: String, value: LLVMValueRef) = currentFunction!!.registerVariable(varName, value)
@@ -89,59 +82,78 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
fun FunctionDescriptor.registerVariable(varName: String, value: LLVMValueRef?) = variables.put(varName, value)
private fun FunctionDescriptor.variable(varName: String): LLVMValueRef? = variables[varName]
fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildAdd (context.llvmBuilder, arg0, arg1, result)!!
fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildMul (context.llvmBuilder, arg0, arg1, result)!!
fun minus (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSub (context.llvmBuilder, arg0, arg1, result)!!
fun div (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSDiv(context.llvmBuilder, arg0, arg1, result)!!
fun srem (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSRem(context.llvmBuilder, arg0, arg1, result)!!
fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildAdd (builder, arg0, arg1, result)!!
fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildMul (builder, arg0, arg1, result)!!
fun minus (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSub (builder, arg0, arg1, result)!!
fun div (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSDiv(builder, arg0, arg1, result)!!
fun srem (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSRem(builder, arg0, arg1, result)!!
/* integers comparisons */
fun icmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntEQ, arg0, arg1, result)!!
fun icmpGt(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSGT, arg0, arg1, result)!!
fun icmpGe(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSGE, arg0, arg1, result)!!
fun icmpLt(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSLT, arg0, arg1, result)!!
fun icmpLe(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSLE, arg0, arg1, result)!!
fun icmpNe(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntNE, arg0, arg1, result)!!
fun icmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, arg0, arg1, result)!!
fun icmpGt(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGT, arg0, arg1, result)!!
fun icmpGe(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGE, arg0, arg1, result)!!
fun icmpLt(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLT, arg0, arg1, result)!!
fun icmpLe(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLE, arg0, arg1, result)!!
fun icmpNe(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntNE, arg0, arg1, result)!!
/* floating-point comparisons */
fun fcmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildFCmp(context.llvmBuilder, LLVMRealPredicate.LLVMRealOEQ, arg0, arg1, result)!!
fun fcmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildFCmp(builder, LLVMRealPredicate.LLVMRealOEQ, arg0, arg1, result)!!
fun bitcast(type: LLVMTypeRef?, value: LLVMValueRef, result: String) = LLVMBuildBitCast(context.llvmBuilder, value, type, result)
fun bitcast(type: LLVMTypeRef?, value: LLVMValueRef, result: String) = LLVMBuildBitCast(builder, value, type, result)!!
fun alloca(type: KotlinType, varName: String): LLVMValueRef = alloca( getLLVMType(type), varName)
fun alloca(type: LLVMTypeRef?, varName: String): LLVMValueRef = LLVMBuildAlloca(context.llvmBuilder, type, varName)!!
fun load(value: LLVMValueRef, varName: String): LLVMValueRef = LLVMBuildLoad(context.llvmBuilder, value, varName)!!
fun store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(context.llvmBuilder, value, ptr)!!
fun alloca(type: LLVMTypeRef?, varName: String): LLVMValueRef = LLVMBuildAlloca(builder, type, varName)!!
fun load(value: LLVMValueRef, varName: String): LLVMValueRef = LLVMBuildLoad(builder, value, varName)!!
fun store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(builder, value, ptr)!!
//-------------------------------------------------------------------------//
fun call(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>, result: String?): LLVMValueRef? {
if (args.size == 0) return LLVMBuildCall(context.llvmBuilder, llvmFunction, null, 0, result)
fun invoke(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>,
then: LLVMBasicBlockRef, landingpad: LLVMBasicBlockRef,
result: String?): LLVMValueRef {
memScoped {
val rargs = allocArrayOf(args)
return LLVMBuildCall(context.llvmBuilder, llvmFunction, rargs[0].ptr, args.size, result)
val rargs = if (args.size != 0) allocArrayOf(args)[0].ptr else null
return LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, then, landingpad, result)!!
}
}
fun call(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>, result: String?): LLVMValueRef {
memScoped {
val rargs = if (args.size != 0) allocArrayOf(args)[0].ptr else null
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, result)!!
}
}
//-------------------------------------------------------------------------//
fun trap() {
// LLVM doesn't seem to provide API to get intrinsics;
// workaround this by declaring the intrinsic explicitly:
val trapFun = LLVMGetNamedFunction(context.llvmModule, "llvm.trap") ?:
LLVMAddFunction(context.llvmModule, "llvm.trap", LLVMFunctionType(LLVMVoidType(), null, 0, 0))!!
LLVMBuildCall(context.llvmBuilder, trapFun, null, 0, "")
// LLVM seems to require an explicit return instruction even after noreturn intrinsic:
val returnType = LLVMGetReturnType(getFunctionType(currentFunction!!.llvmFunction.getLlvmValue()))
LLVMBuildRet(context.llvmBuilder, LLVMConstNull(returnType))
fun phi(type: LLVMTypeRef, result: String): LLVMValueRef {
return LLVMBuildPhi(builder, type, result)!!
}
fun addPhiIncoming(phi: LLVMValueRef, vararg incoming: Pair<LLVMBasicBlockRef, LLVMValueRef>) {
memScoped {
val incomingValues = allocArrayOf(incoming.map { it.second })
val incomingBlocks = allocArrayOf(incoming.map { it.first })
LLVMAddIncoming(phi, incomingValues[0].ptr, incomingBlocks[0].ptr, incoming.size)
}
}
fun assignPhis(vararg phiToValue: Pair<LLVMValueRef, LLVMValueRef>) {
val currentBlock = this.currentBlock
phiToValue.forEach {
addPhiIncoming(it.first, currentBlock to it.second)
}
}
//-------------------------------------------------------------------------//
/* to class descriptor */
fun classType(descriptor: ClassDescriptor): LLVMTypeRef = LLVMGetTypeByName(context.llvmModule, descriptor.symbolName)!!
fun typeInfoType(descriptor: ClassDescriptor): LLVMTypeRef? = descriptor.llvmTypeInfoPtr.getLlvmType()
fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef? = descriptor.llvmTypeInfoPtr.getLlvmValue()
fun typeInfoType(descriptor: ClassDescriptor): LLVMTypeRef = descriptor.llvmTypeInfoPtr.getLlvmType()
fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr.getLlvmValue()!!
fun thisVariable() = variable("this")!!
fun param(fn: FunctionDescriptor?, i: Int): LLVMValueRef? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i)
@@ -149,21 +161,124 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
fun indexInClass(p:PropertyDescriptor):Int = (p.containingDeclaration as ClassDescriptor).fields.indexOf(p)
fun basicBlock(): LLVMBasicBlockRef? = LLVMAppendBasicBlock(currentFunction!!.llvmFunction.getLlvmValue(), currentFunction!!.bbLabel())
fun basicBlock(name: String = "label_"): LLVMBasicBlockRef =
LLVMAppendBasicBlock(currentFunction!!.llvmFunction.getLlvmValue(), name)!!
fun basicBlock(name: String, code: () -> Unit) = basicBlock(name).apply {
appendingTo(this) {
code()
}
}
fun lastBasicBlock(): LLVMBasicBlockRef? = LLVMGetLastBasicBlock(currentFunction!!.llvmFunction.getLlvmValue())
fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction.getLlvmValue()
fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef? = descriptor.functionName.localHash.getLlvmValue()
fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction.getLlvmValue()!!
fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.getLlvmValue()!!
fun br(bbLabel: LLVMBasicBlockRef) = LLVMBuildBr(context.llvmBuilder, bbLabel)
fun condBr(condition: LLVMValueRef?, bbTrue: LLVMBasicBlockRef?, bbFalse: LLVMBasicBlockRef?)
= LLVMBuildCondBr(context.llvmBuilder, condition, bbTrue, bbFalse)
fun br(bbLabel: LLVMBasicBlockRef): LLVMValueRef {
val res = LLVMBuildBr(builder, bbLabel)!!
currentPositionHolder.setAfterTerminator()
return res
}
fun positionAtEnd(bbLabel: LLVMBasicBlockRef)
= LLVMPositionBuilderAtEnd(context.llvmBuilder, bbLabel)
fun condBr(condition: LLVMValueRef?, bbTrue: LLVMBasicBlockRef?, bbFalse: LLVMBasicBlockRef?): LLVMValueRef? {
val res = LLVMBuildCondBr(builder, condition, bbTrue, bbFalse)
currentPositionHolder.setAfterTerminator()
return res
}
fun ret(value: LLVMValueRef?): LLVMValueRef {
val res = LLVMBuildRet(builder, value)!!
currentPositionHolder.setAfterTerminator()
return res
}
fun unreachable(): LLVMValueRef? {
val res = LLVMBuildUnreachable(builder)
currentPositionHolder.setAfterTerminator()
return res
}
//-------------------------------------------------------------------------//
/**
* Represents the mutable position of instructions being inserted.
*
* This class is introduced to workaround unreachable code handling.
*/
inner class PositionHolder {
private val builder: LLVMBuilderRef = LLVMCreateBuilder()!!
fun getBuilder(): LLVMBuilderRef {
if (isAfterTerminator) {
positionAtEnd(basicBlock("unreachable"))
}
return builder
}
/**
* Should be `true` iff the position is located after terminator instruction.
*/
var isAfterTerminator: Boolean = false
private set
fun setAfterTerminator() {
isAfterTerminator = true
}
val currentBlock: LLVMBasicBlockRef
get() = LLVMGetInsertBlock(builder)!!
fun positionAtEnd(block: LLVMBasicBlockRef) {
LLVMPositionBuilderAtEnd(builder, block)
val lastInstr = LLVMGetLastInstruction(block)
isAfterTerminator = lastInstr != null && (LLVMIsATerminatorInst(lastInstr) != null)
}
fun dispose() {
LLVMDisposeBuilder(builder)
}
}
private var currentPositionHolder: PositionHolder = PositionHolder()
/**
* Returns `true` iff the current code generation position is located after terminator instruction.
*/
fun isAfterTerminator() = currentPositionHolder.isAfterTerminator
val currentBlock: LLVMBasicBlockRef
get() = currentPositionHolder.currentBlock
/**
* The builder representing the current code generation position.
*
* Note that it shouldn't be positioned directly using LLVM API due to some hacks.
* Use e.g. [positionAtEnd] instead. See [PositionHolder] for details.
*/
val builder: LLVMBuilderRef
get() = currentPositionHolder.getBuilder()
fun positionAtEnd(bbLabel: LLVMBasicBlockRef) = currentPositionHolder.positionAtEnd(bbLabel)
inline fun <R> preservingPosition(code: () -> R): R {
val oldPositionHolder = currentPositionHolder
val newPositionHolder = PositionHolder()
currentPositionHolder = newPositionHolder
try {
return code()
} finally {
currentPositionHolder = oldPositionHolder
newPositionHolder.dispose()
}
}
inline fun <R> appendingTo(block: LLVMBasicBlockRef, code: CodeGenerator.() -> R) = preservingPosition {
positionAtEnd(block)
code()
}
fun ret(value: LLVMValueRef?) = LLVMBuildRet(context.llvmBuilder, value)
fun unreachable(): LLVMValueRef? = LLVMBuildUnreachable(context.llvmBuilder)
}
@@ -7,8 +7,6 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
internal class Context(val irModule: IrModuleFragment, val runtime: Runtime, val llvmModule: LLVMModuleRef) {
val moduleIndex = ModuleIndex(irModule)
val llvmBuilder = LLVMCreateBuilder()
private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
if (LLVMGetNamedFunction(llvmModule, name) != null) {
throw IllegalArgumentException("function $name already exists")
@@ -31,8 +29,4 @@ internal class Context(val irModule: IrModuleFragment, val runtime: Runtime, val
val isInstanceFunction = importRtFunction("IsInstance")
val checkInstanceFunction = importRtFunction("CheckInstance")
val throwExceptionFunction = importRtFunction("ThrowException")
fun dispose() {
LLVMDisposeBuilder(llvmBuilder)
}
}
@@ -26,7 +26,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose
@@ -90,6 +92,71 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
// TODO: consider eliminating mutable state
private var currentCodeContext: CodeContext = TopLevelCodeContext
/**
* Defines how to generate context-dependent operations.
*/
private interface CodeContext {
fun genReturn(target: CallableDescriptor, value: LLVMValueRef?)
fun genBreak(loop: IrLoop)
fun genContinue(loop: IrLoop)
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?): LLVMValueRef
fun genThrow(exception: LLVMValueRef)
}
/**
* Fake [CodeContext] that doesn't support any operation.
*
* During function code generation [FunctionScope] should be set up.
*/
private object TopLevelCodeContext : CodeContext {
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) = throw UnsupportedOperationException()
override fun genBreak(loop: IrLoop) = throw UnsupportedOperationException()
override fun genContinue(loop: IrLoop) = throw UnsupportedOperationException()
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?)
= throw UnsupportedOperationException()
override fun genThrow(exception: LLVMValueRef) = throw UnsupportedOperationException()
}
/**
* The [CodeContext] which can define some operations and delegate other ones to [outerContext]
*/
private abstract class InnerScope(val outerContext: CodeContext) : CodeContext by outerContext
/**
* Convenient [InnerScope] implementation that is bound to the [currentCodeContext].
*/
private abstract inner class InnerScopeImpl : InnerScope(currentCodeContext)
/**
* Executes [block] with [codeContext] substituted as [currentCodeContext].
*/
private inline fun <R> using(codeContext: CodeContext?, block: () -> R): R {
val oldCodeContext = currentCodeContext
if (codeContext != null) {
currentCodeContext = codeContext
}
try {
return block()
} finally {
currentCodeContext = oldCodeContext
}
}
//-------------------------------------------------------------------------//
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
@@ -121,17 +188,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val loopBody = codegen.basicBlock()
val loopExit = codegen.basicBlock()
LLVMBuildBr(context.llvmBuilder, loopEnter)
codegen.br(loopEnter)
codegen.positionAtEnd(loopEnter!!)
codegen.positionAtEnd(loopEnter)
val condition = evaluateExpression(codegen.newVar(), loop.condition)
LLVMBuildCondBr(context.llvmBuilder, condition, loopBody, loopExit)
codegen.condBr(condition, loopBody, loopExit)
codegen.positionAtEnd(loopBody!!)
codegen.positionAtEnd(loopBody)
evaluateExpression(codegen.newVar(), loop.body)
LLVMBuildBr(context.llvmBuilder, loopEnter)
codegen.positionAtEnd(loopExit!!)
codegen.br(loopEnter)
codegen.positionAtEnd(loopExit)
}
//-------------------------------------------------------------------------//
@@ -141,17 +208,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val loopCheck = codegen.basicBlock()
val loopExit = codegen.basicBlock()
LLVMBuildBr(context.llvmBuilder, loopBody)
codegen.br(loopBody)
codegen.positionAtEnd(loopBody!!)
codegen.positionAtEnd(loopBody)
evaluateExpression(codegen.newVar(), loop.body)
LLVMBuildBr(context.llvmBuilder, loopCheck)
codegen.br(loopCheck)
codegen.positionAtEnd(loopCheck!!)
codegen.positionAtEnd(loopCheck)
val condition = evaluateExpression(codegen.newVar(), loop.condition)
LLVMBuildCondBr(context.llvmBuilder, condition, loopBody, loopExit)
codegen.condBr(condition, loopBody, loopExit)
codegen.positionAtEnd(loopExit!!)
codegen.positionAtEnd(loopExit)
}
//-------------------------------------------------------------------------//
@@ -162,53 +229,55 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val classDescriptor = DescriptorUtils.getContainingClass(constructorDescriptor)
val thisPtr = codegen.load(codegen.thisVariable(), codegen.newVar())
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
using(FunctionScope(constructorDeclaration)) {
if (!skipConstructorBodyGeneration(constructorDeclaration))
constructorDeclaration.acceptChildrenVoid(this)
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
if (constructorDescriptor.isPrimary && !DescriptorUtils.isCompanionObject(constructorDescriptor.constructedClass)) {
val irOfCurrentClass = context.moduleIndex.classes[classDescriptor!!.classId]
irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
if (!skipConstructorBodyGeneration(constructorDeclaration))
constructorDeclaration.acceptChildrenVoid(this)
override fun visitField(fieldDeclaration: IrField) {
val fieldDescriptor = fieldDeclaration.descriptor
val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor)
var value:LLVMValueRef? = null
if (constructorDescriptor.valueParameters.any{ it.name == fieldDescriptor.name }) {
val variable = codegen.variable(fieldDescriptor.name.asString())
value = codegen.load(variable!!, codegen.newVar())
if (constructorDescriptor.isPrimary && !DescriptorUtils.isCompanionObject(constructorDescriptor.constructedClass)) {
val irOfCurrentClass = context.moduleIndex.classes[classDescriptor!!.classId]
irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
else {
value = evaluateExpression(codegen.newVar(), fieldDeclaration.initializer)
override fun visitField(fieldDeclaration: IrField) {
val fieldDescriptor = fieldDeclaration.descriptor
val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor)
var value: LLVMValueRef? = null
if (constructorDescriptor.valueParameters.any { it.name == fieldDescriptor.name }) {
val variable = codegen.variable(fieldDescriptor.name.asString())
value = codegen.load(variable!!, codegen.newVar())
} else {
value = evaluateExpression(codegen.newVar(), fieldDeclaration.initializer)
}
if (value != null)
codegen.store(value, fieldPtr!!)
}
if (value != null)
codegen.store(value!!, fieldPtr!!)
}
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
evaluateExpression("", declaration.body)
}
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
evaluateExpression("", declaration.body)
}
override fun visitClass(declaration: IrClass) {
return
}
override fun visitClass(declaration: IrClass) {
return
}
override fun visitConstructor(declaration: IrConstructor) {
return
}
})
override fun visitConstructor(declaration: IrConstructor) {
return
}
})
}
}
codegen.ret(thisPtr)
@@ -225,9 +294,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
override fun visitBlockBody(body: IrBlockBody) {
super.visitBlockBody(body)
if (KotlinBuiltIns.isUnit(codegen.currentFunction!!.returnType!!)
&& body.statements.lastOrNull() !is IrThrow) { // Don't try generate return at the end of the throwing block.
codegen.ret(null)
val function = codegen.currentFunction!!
if (function !is ConstructorDescriptor && !codegen.isAfterTerminator()) {
if (function.returnType!!.isUnit()) {
codegen.ret(null)
} else {
codegen.unreachable()
}
}
logger.log("visitBlockBody : ${ir2string(body)}")
}
@@ -256,13 +329,48 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
override fun visitTry(expression: IrTry) {
logger.log("visitTry : ${ir2string(expression)}")
evaluateExpression("", expression)
}
//-------------------------------------------------------------------------//
/**
* The [CodeContext] enclosing the entire function body.
*/
private inner class FunctionScope(val declaration: IrFunction) : InnerScopeImpl() {
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
if (target == declaration.descriptor) {
codegen.ret(value)
} else {
super.genReturn(target, value)
}
}
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?)
= codegen.call(function, args, result)
override fun genThrow(exception: LLVMValueRef) {
val objHeaderPtr = codegen.bitcast(kObjHeaderPtr, exception, codegen.newVar())
val args = listOf(objHeaderPtr)
codegen.call(context.throwExceptionFunction, args, "")
codegen.unreachable()
}
}
override fun visitFunction(declaration: IrFunction) {
logger.log("visitFunction : ${ir2string(declaration)}")
if (declaration.descriptor.modality == Modality.ABSTRACT || declaration.body == null)
return
codegen.function(declaration)
metadator.function(declaration)
declaration.acceptChildrenVoid(this)
using(FunctionScope(declaration)) {
declaration.acceptChildrenVoid(this)
}
verifyModule(context.llvmModule)
}
@@ -290,10 +398,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
logger.log("visitVariable : ${ir2string(declaration)}")
val variableName = declaration.descriptor.name.asString()
val variableType = declaration.descriptor.type
val newVariable = codegen.alloca(variableType, variableName) // Create LLVM variable.
codegen.registerVariable(variableName, newVariable) // Map variableName -> LLVM variable.
val value = evaluateExpression(variableName, declaration.initializer) // Generate initialization code.
codegen.store(value!!, codegen.variable(variableName)!!) // Store init result in the variable
val value = evaluateExpression("", declaration.initializer) // Generate initialization code.
createVariable(declaration.descriptor, value) // Create and initialize variable.
}
private fun createVariable(descriptor: VariableDescriptor, value: LLVMValueRef? = null): LLVMValueRef {
val name = descriptor.name.asString()
val type = descriptor.type
val newVariable = codegen.alloca(type, name) // Create LLVM variable.
codegen.registerVariable(name, newVariable) // Map variableName -> LLVM variable.
if (value != null) {
codegen.store(value, newVariable)
}
return newVariable
}
//-------------------------------------------------------------------------//
@@ -380,6 +499,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
is IrExpressionBody -> return evaluateExpression (tmpVariableName, value.expression)
is IrWhen -> return evaluateWhen (tmpVariableName, value)
is IrThrow -> return evaluateThrow (tmpVariableName, value)
is IrTry -> return evaluateTry ( value)
is IrStringConcatenation -> return evaluateStringConcatenation(tmpVariableName, value)
is IrBlockBody -> return evaluateBlock ( value as IrStatementContainer)
is IrWhileLoop -> return evaluateWhileLoop ( value)
@@ -390,14 +510,91 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
}
private fun evaluateExpressionAndJump(expression: IrExpression, destination: ContinuationBlock) {
val result = evaluateExpression("", expression)
if (!codegen.isAfterTerminator()) {
jump(destination, result)
} else {
// Workaround for unreachable code handling.
// Note: cannot rely on checking that expression type is Nothing.
}
}
//-------------------------------------------------------------------------//
/**
* Represents the basic block which may expect a value:
* when generating a [jump] to this block, one should provide the value.
* Inside the block that value is accessible as [valuePhi].
*
* This class is designed to be used to generate Kotlin expressions that have a value and require branching.
*
* [valuePhi] may be `null`, which would mean that no value is passed.
*/
private data class ContinuationBlock(val block: LLVMBasicBlockRef, val valuePhi: LLVMValueRef?)
/**
* Jumps to [target] passing [value].
*/
private fun jump(target: ContinuationBlock, value: LLVMValueRef?) {
val entry = target.block
codegen.br(entry)
if (target.valuePhi != null) {
codegen.assignPhis(target.valuePhi to value!!)
}
}
/**
* Creates new [ContinuationBlock] and generates [code] starting from its' beginning.
*/
private inline fun continuationBlock(type: LLVMTypeRef, code: (LLVMValueRef) -> Unit): ContinuationBlock {
val entry = codegen.basicBlock()
codegen.appendingTo(entry) {
val valuePhi = codegen.phi(type, codegen.newVar())
code(valuePhi)
return ContinuationBlock(entry, valuePhi)
}
}
/**
* Creates new [ContinuationBlock] that don't receive the value and generates [code] starting from its' beginning.
*/
private inline fun continuationBlock(code: () -> Unit): ContinuationBlock {
val block = codegen.basicBlock()
codegen.appendingTo(block) {
code()
}
return ContinuationBlock(block, null)
}
/**
* Creates new [ContinuationBlock] that receives the value of type corresponding to given Kotlin type
* and generates [code] starting from its' beginning.
*/
private fun continuationBlock(type: KotlinType, code: (LLVMValueRef?) -> Unit = {}): ContinuationBlock {
return if (type.isUnitOrNothing()) {
continuationBlock {
code(null)
}
} else {
continuationBlock(getLLVMType(type), code)
}
}
//-------------------------------------------------------------------------//
private fun evaluateStringConcatenation(tmpVariableName: String, value: IrStringConcatenation): LLVMValueRef? {
val stringPlus = KonanPlatform.builtIns.stringType.memberScope.getContributedFunctions(Name.identifier("plus"), NoLookupLocation.FROM_BACKEND).first()
var res:LLVMValueRef? = null
val strings:List<LLVMValueRef?> = value.arguments.map {
val strings:List<LLVMValueRef> = value.arguments.map {
val descriptor = getToString(it.type)
val args = listOf(evaluateExpression(codegen.newVar(), it))
return@map evaluateSimpleFunctionCall(codegen.newVar(), descriptor, args)!!
val args = listOf(evaluateExpression(codegen.newVar(), it)!!)
return@map evaluateSimpleFunctionCall(codegen.newVar(), descriptor, args)
}
val concatResult = strings.take(1).fold(strings.first()) {res, it -> evaluateSimpleFunctionCall(codegen.newVar(), stringPlus, listOf(res, it))}
return concatResult
@@ -407,11 +604,223 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateThrow(tmpVariableName: String, expression: IrThrow): LLVMValueRef? {
val objPointer = evaluateExpression(codegen.newVar(), expression.value)
val objHeaderPtr = codegen.bitcast(kObjHeaderPtr, objPointer!!, codegen.newVar())
val args = listOf(objHeaderPtr) // Create arg list.
codegen.call(context.throwExceptionFunction, args, "")
return codegen.unreachable()
val exception = evaluateExpression(codegen.newVar(), expression.value)!!
currentCodeContext.genThrow(exception)
return null
}
//-------------------------------------------------------------------------//
/**
* The [CodeContext] that catches exceptions.
*/
private inner abstract class CatchingScope : InnerScopeImpl() {
/**
* The LLVM `landingpad` such that if invoked function throws an exception,
* then this exception is passed to [catch].
*/
private val landingpad: LLVMBasicBlockRef by lazy {
using(outerContext) {
codegen.basicBlock("landingpad") {
genLandingpad()
}
}
}
/**
* The Kotlin exception handler, i.e. the [ContinuationBlock] which gets started
* when the exception is caught, receiving this exception as its' value.
*/
private val catch by lazy {
using(outerContext) {
continuationBlock(kInt8Ptr) { exception ->
genHandler(exception)
}
}
}
private fun jumpToHandler(exception: LLVMValueRef) {
val catch = this.catch
jump(catch, exception)
}
/**
* Generates the LLVM `landingpad` that catches C++ exception with type `KotlinException`,
* unwraps the Kotlin exception object and jumps to [catch].
*/
private fun genLandingpad() {
with(codegen) {
val lpType = structType(int8TypePtr, int32Type)
val persFn = externalFunction("__gxx_personality_v0", functionType(int32Type, true))
val persFnRaw = LLVMConstBitCast(persFn, int8TypePtr)!!
val lp = LLVMBuildLandingPad(codegen.builder, lpType, persFnRaw, 1, "lp")
LLVMAddClause(lp, externalGlobal("_ZTI15KotlinException", int8Type))
// FIXME: properly handle C++ exceptions: currently C++ exception can be thrown out from try-finally
// bypassing the finally block.
val exceptionRecord = LLVMBuildExtractValue(codegen.builder, lp, 0, "er")
val beginCatch = externalFunction("__cxa_begin_catch", functionType(int8TypePtr, false, int8TypePtr))
val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord), "")
val exceptionPtr = bitcast(pointerType(int8TypePtr), exceptionRawPtr, "")
val exception = load(exceptionPtr, "exception")
val endCatch = externalFunction("__cxa_end_catch", functionType(voidType, false))
call(endCatch, listOf(), "")
jumpToHandler(exception)
}
}
// The call inside [CatchingScope] must be configured to dispatch exception to the scope's handler.
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?): LLVMValueRef {
val then = codegen.basicBlock()
val res = codegen.invoke(function, args, then, landingpad, result)
codegen.positionAtEnd(then)
return res
}
override fun genThrow(exception: LLVMValueRef) {
jumpToHandler(exception)
}
protected abstract fun genHandler(exception: LLVMValueRef)
}
/**
* The [CatchingScope] that handles exceptions using Kotlin `catch` clauses.
*
* @param success the block to be used when the exception is successfully handled;
* expects `catch` expression result as its' value.
*/
private inner class CatchScope(private val catches: List<IrCatch>,
private val success: ContinuationBlock) : CatchingScope() {
override fun genHandler(exception: LLVMValueRef) {
// TODO: optimize for `Throwable` clause.
catches.forEach {
val isInstance = genInstanceOf("", exception, it.parameter.type)
val body = codegen.basicBlock("catch")
val nextCheck = codegen.basicBlock("catchCheck")
codegen.condBr(isInstance, body, nextCheck)
codegen.appendingTo(body) {
createVariable(it.parameter, exception)
evaluateExpressionAndJump(it.result, success)
}
codegen.positionAtEnd(nextCheck)
}
// rethrow the exception if no clause can handle it.
outerContext.genThrow(exception)
}
}
/**
* The [InnerScope] that includes code generated by [genFinalize] when leaving it
* with `return`, `break`, `continue` or throwing exception.
*/
private abstract inner class FinalizingScope() : CatchingScope() {
/**
* The [ContinuationBlock] to be used for `return` from the function.
* Expects return value as its' value.
*/
private val returnFromCurrent: ContinuationBlock by lazy {
using(outerContext) {
val target = codegen.currentFunction!!
continuationBlock(target.returnType!!) { returnValue ->
genFinalize()
outerContext.genReturn(target, returnValue)
}
}
}
// Jump to finalize-and-return instead of simply returning.
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
if (target != codegen.currentFunction) {
TODO()
}
jump(returnFromCurrent, value)
}
override fun genBreak(loop: IrLoop) = TODO()
override fun genContinue(loop: IrLoop) = TODO()
// When an exception is caught, finalize the scope and rethrow the exception.
override fun genHandler(exception: LLVMValueRef) {
genFinalize()
outerContext.genThrow(exception)
}
protected abstract fun genFinalize()
}
/**
* Generates the code which gets "finalized" exactly once when completed either normally or abnormally.
*
* @param code generates the code to be post-dominated by cleanup.
* It must jump to given [ContinuationBlock] with its' result when completed normally.
*
* @param finalize generates the cleanup code that must be executed when code generated by [code] is completed.
*
* @param type Kotlin type of the result of generated code.
*
* @return the result of the generated code.
*/
private fun genFinalizedBy(finalize: (() -> Unit)?,
type: KotlinType, code: (ContinuationBlock) -> Unit): LLVMValueRef? {
val scope = if (finalize == null) null else {
object : FinalizingScope() {
override fun genFinalize() {
finalize()
}
}
}
val continuation = continuationBlock(type)
using(scope) {
code(continuation)
}
codegen.positionAtEnd(continuation.block)
finalize?.invoke()
// TODO: finalize is duplicated many times (just as in C++, Java or Kotlin JVM);
// it is very important to optimize this.
return continuation.valuePhi
}
/**
* Generates code that is "finalized" by given expression.
*/
private fun genFinalizedBy(finalize: IrExpression?, type: KotlinType,
code: (ContinuationBlock) -> Unit): LLVMValueRef? {
return genFinalizedBy({ evaluateExpression("", finalize) }, type, code)
}
private fun KotlinType.isUnitOrNothing() = isUnit() || isNothing()
private fun evaluateTry(expression: IrTry): LLVMValueRef? {
// TODO: does basic block order influence machine code order?
// If so, consider reordering blocks to reduce exception tables size.
return genFinalizedBy(expression.finallyExpression, expression.type) { continuation ->
val catch = if (expression.catches.isEmpty()) null else CatchScope(expression.catches, continuation)
using(catch) {
evaluateExpressionAndJump(expression.tryResult, continuation)
}
}
}
//-------------------------------------------------------------------------//
@@ -527,7 +936,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val srcArg = evaluateExpression(codegen.newVar(), value.argument)!! // Evaluate src expression.
val srcObjInfoPtr = codegen.bitcast(kObjHeaderPtr, srcArg, codegen.newVar()) // Cast src to ObjInfoPtr.
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
codegen.call(context.checkInstanceFunction, args, "") // Check if dst is subclass of src.
currentCodeContext.genCall(context.checkInstanceFunction, args, "") // Check if dst is subclass of src.
return srcArg
}
@@ -536,21 +945,29 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun evaluateInstanceOf(tmpVariableName: String, value: IrTypeOperatorCall): LLVMValueRef {
logger.log("evaluateInstanceOf : ${ir2string(value)}")
val dstDescriptor = TypeUtils.getClassDescriptor(value.typeOperand) // Get class descriptor for dst type.
val type = value.typeOperand
val srcArg = evaluateExpression(codegen.newVar(), value.argument)!! // Evaluate src expression.
return genInstanceOf(tmpVariableName, srcArg, type)
}
private fun genInstanceOf(tmpVariableName: String, obj: LLVMValueRef, type: KotlinType): LLVMValueRef {
val dstDescriptor = TypeUtils.getClassDescriptor(type) // Get class descriptor for dst type.
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor!!) // Get TypeInfo for dst type.
val srcArg = evaluateExpression(codegen.newVar(), value.argument)!! // Evaluate src expression.
val srcObjInfoPtr = codegen.bitcast(kObjHeaderPtr, srcArg, codegen.newVar()) // Cast src to ObjInfoPtr.
val srcObjInfoPtr = codegen.bitcast(kObjHeaderPtr, obj, codegen.newVar()) // Cast src to ObjInfoPtr.
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
val result = codegen.call(context.isInstanceFunction, args, codegen.newVar()) // Check if dst is subclass of src.
return LLVMBuildTrunc(context.llvmBuilder, result!!, kInt1, tmpVariableName)!! // Truncate result to boolean
val result = currentCodeContext.genCall( // Check if dst is subclass of src.
context.isInstanceFunction, args, codegen.newVar())
return LLVMBuildTrunc(codegen.builder, result, kInt1, tmpVariableName)!! // Truncate result to boolean
}
//-------------------------------------------------------------------------//
private fun evaluateNotInstanceOf(tmpVariableName: String, value: IrTypeOperatorCall): LLVMValueRef {
val instanceOfResult = evaluateInstanceOf(codegen.newVar(), value)
return LLVMBuildNot(context.llvmBuilder, instanceOfResult, tmpVariableName)!!
return LLVMBuildNot(codegen.builder, instanceOfResult, tmpVariableName)!!
}
//-------------------------------------------------------------------------//
@@ -621,9 +1038,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val typePtr = pointerType(codegen.classType(value.containingDeclaration as ClassDescriptor))
memScoped {
val args = allocArrayOf(kImmOne)
val objectPtr = LLVMBuildGEP(codegen.context.llvmBuilder, objHeaderPtr, args[0].ptr, 1, codegen.newVar())
val objectPtr = LLVMBuildGEP(codegen.builder, objHeaderPtr, args[0].ptr, 1, codegen.newVar())
val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!, codegen.newVar())
val fieldPtr = LLVMBuildStructGEP(codegen.context.llvmBuilder, typedObjPtr, codegen.indexInClass(value), codegen.newVar())
val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, codegen.indexInClass(value), codegen.newVar())
return fieldPtr
}
}
@@ -653,12 +1070,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateReturn(value: IrReturn): LLVMValueRef? {
logger.log("evaluateReturn : ${ir2string(value)}")
val ret = evaluateExpression(codegen.newVar(), value.value)
if (KotlinBuiltIns.isUnit(value.value.type))
return ret
return codegen.ret(ret)
private fun evaluateReturn(expression: IrReturn): LLVMValueRef? {
logger.log("evaluateReturn : ${ir2string(expression)}")
val value = expression.value
val evaluated = if (value is IrGetObjectValue && value.type.isUnit()) {
// hack to make "return without value" work
null
} else {
evaluateExpression(codegen.newVar(), value)
}
val ret = if (!value.type.isUnit()) {
evaluated
} else {
null // hack for bad Unit type handling
}
currentCodeContext.genReturn(expression.returnTarget, ret)
return null
}
//-------------------------------------------------------------------------//
@@ -673,13 +1103,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression?): LLVMValueRef? {
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression?): LLVMValueRef {
logger.log("evaluateCall : $tmpVariableName = ${ir2string(value)}")
val args = mutableListOf<LLVMValueRef?>() // Create list of function args.
val args = mutableListOf<LLVMValueRef>() // Create list of function args.
value!!.acceptChildrenVoid(object: IrElementVisitorVoid { // Iterate args of the function.
override fun visitElement(element: IrElement) { // Visit arg.
val tmp = codegen.newVar() // Create variable representing the arg in codegen
args.add(evaluateExpression(tmp, element as IrExpression)) // Evaluate expression and get LLVM arg
args.add(evaluateExpression(tmp, element as IrExpression)!!) // Evaluate expression and get LLVM arg
}
})
@@ -694,7 +1124,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: List<LLVMValueRef?>): LLVMValueRef? {
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
when (descriptor) {
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (tmpVariableName, callee, args)
@@ -705,7 +1135,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateSimpleFunctionCall(tmpVariableName: String, descriptor: FunctionDescriptor, args: List<LLVMValueRef?>): LLVMValueRef? {
private fun evaluateSimpleFunctionCall(tmpVariableName: String, descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
//logger.log("evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}")
if (descriptor.isOverridable)
return callVirtual(descriptor, args, tmpVariableName)
@@ -717,28 +1147,28 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun evaluateSetterCall(tmpVariableName: String, value: IrSetterCallImpl): LLVMValueRef? {
val descriptor = value.descriptor as FunctionDescriptor
val args = mutableListOf<LLVMValueRef?>()
val args = mutableListOf<LLVMValueRef>()
if (descriptor.dispatchReceiverParameter != null)
args.add(evaluateExpression(codegen.newVar(), value.dispatchReceiver)) //add this ptr
args.add(evaluateExpression(codegen.newVar(), value.getValueArgument(0)))
args.add(evaluateExpression(codegen.newVar(), value.dispatchReceiver)!!) //add this ptr
args.add(evaluateExpression(codegen.newVar(), value.getValueArgument(0))!!)
return evaluateSimpleFunctionCall(tmpVariableName, descriptor, args)
}
//-------------------------------------------------------------------------//
private fun evaluateConstructorCall(variableName: String, callee: IrCall, args: List<LLVMValueRef?>): LLVMValueRef? {
private fun evaluateConstructorCall(variableName: String, callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
logger.log("evaluateConstructorCall : $variableName = ${ir2string(callee)}")
memScoped {
val containingClass = (callee.descriptor as ClassConstructorDescriptor).containingDeclaration
val typeInfo = codegen.typeInfoValue(containingClass)
val allocHint = Int32(1).getLlvmValue()
val allocHint = Int32(1).getLlvmValue()!!
val thisValue = if (containingClass.isArray) {
assert(args.size == 1 && LLVMTypeOf(args[0]) == LLVMInt32Type())
codegen.call(context.allocArrayFunction, listOf(typeInfo, allocHint, args[0]), variableName)
currentCodeContext.genCall(context.allocArrayFunction, listOf(typeInfo, allocHint, args[0]), variableName)
} else {
codegen.call(context.allocInstanceFunction, listOf(typeInfo, allocHint), variableName)
currentCodeContext.genCall(context.allocInstanceFunction, listOf(typeInfo, allocHint), variableName)
}
val constructorParams: MutableList<LLVMValueRef?> = mutableListOf()
val constructorParams: MutableList<LLVMValueRef> = mutableListOf()
constructorParams += thisValue
constructorParams += args
return evaluateSimpleFunctionCall(variableName, callee.descriptor as FunctionDescriptor, constructorParams)
@@ -817,9 +1247,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val arg0Type = callee.argument0.type
val descriptor = getEquals(arg0Type, "equals") // Get descriptor for "arg0.equals".
if (arg0Type.isMarkedNullable) { // If arg0 is nullable.
val bbEq2 = codegen.basicBlock()!! // Block to process "eqeq".
val bbEq3 = codegen.basicBlock()!! // Block to process "eqeqeq".
val bbExit = codegen.basicBlock()!! // Exit block for feather generation.
val bbEq2 = codegen.basicBlock() // Block to process "eqeq".
val bbEq3 = codegen.basicBlock() // Block to process "eqeqeq".
val bbExit = codegen.basicBlock() // Exit block for feather generation.
val result = codegen.alloca(getLLVMType(callee.type), codegen.newVar())
val condition = codegen.icmpEq(arg0, kNullPtr, codegen.newVar()) // Compare arg0 with "null".
@@ -831,14 +1261,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
codegen.br(bbExit) //
codegen.positionAtEnd(bbEq2) // Get generation to bbEq2.
val resultEquals = evaluateSimpleFunctionCall(codegen.newVar(), descriptor, listOf(arg0, arg1))!!
val resultEquals = evaluateSimpleFunctionCall(codegen.newVar(), descriptor, listOf(arg0, arg1))
codegen.store(resultEquals, result) // Store "eqeqeq" result in "result".
codegen.br(bbExit) //
codegen.positionAtEnd(bbExit) // Get generation to bbExit.
return codegen.load(result, tmpVariableName) // Load result in tmpVariable.
} else {
return evaluateSimpleFunctionCall(tmpVariableName, descriptor, listOf(arg0, arg1))!!
return evaluateSimpleFunctionCall(tmpVariableName, descriptor, listOf(arg0, arg1))
}
}
@@ -872,7 +1302,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val bbCurr = codegen.basicBlock() // Create block for clause body.
val condition = evaluateExpression(codegen.newVar(), branch.condition) // Generate cmp instruction.
codegen.condBr(condition, bbCurr, bbNext) // Conditional branch depending on cmp result.
codegen.positionAtEnd(bbCurr!!) // Switch generation to block for clause body.
codegen.positionAtEnd(bbCurr) // Switch generation to block for clause body.
val brResult = evaluateExpression(codegen.newVar(), branch.result) // Generate clause body.
if (neitherUnitNorNothing) // If nor unit neither result ends with return
codegen.store(brResult!!, resultPtr!!) // we store result to temporal variable.
@@ -891,7 +1321,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef?>, result: String?): LLVMValueRef? {
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef>, result: String?): LLVMValueRef {
val realDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor)
val llvmFunction = codegen.functionLlvmValue(realDescriptor)
return call(descriptor, llvmFunction, args, result)
@@ -911,38 +1341,35 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef?>, result: String?): LLVMValueRef? {
val thisI8PtrPtr = codegen.bitcast(kInt8PtrPtr, args[0]!!, codegen.newVar()) // Cast "this (i8*)" to i8**.
val typeInfoI8Ptr = codegen.load(thisI8PtrPtr!!, codegen.newVar()) // Load TypeInfo address.
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef>, result: String?): LLVMValueRef {
val thisI8PtrPtr = codegen.bitcast(kInt8PtrPtr, args[0], codegen.newVar()) // Cast "this (i8*)" to i8**.
val typeInfoI8Ptr = codegen.load(thisI8PtrPtr, codegen.newVar()) // Load TypeInfo address.
val typeInfoPtr = codegen.bitcast(kTypeInfoPtr, typeInfoI8Ptr, codegen.newVar()) // Cast TypeInfo (i8*) to TypeInfo*.
val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked
val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup
val llvmMethod = codegen.call(
val llvmMethod = currentCodeContext.genCall(
context.lookupOpenMethodFunction,
lookupArgs,
codegen.newVar()) // Get method ptr to be invoked
val functionPtrType = pointerType(getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked
val function = codegen.bitcast(functionPtrType, llvmMethod!!, codegen.newVar()) // Cast method address to the type
val function = codegen.bitcast(functionPtrType, llvmMethod, codegen.newVar()) // Cast method address to the type
return call(descriptor, function, args, result) // Invoke the method
}
//-------------------------------------------------------------------------//
private fun call(descriptor: FunctionDescriptor, function: LLVMValueRef?, args: List<LLVMValueRef?>, result: String?): LLVMValueRef? {
return codegen.call(function, args, if (KotlinBuiltIns.isUnit(descriptor.returnType!!)) "" else result)
private fun call(descriptor: FunctionDescriptor, function: LLVMValueRef, args: List<LLVMValueRef>, result: String?): LLVMValueRef {
return currentCodeContext.genCall(function, args,
if (KotlinBuiltIns.isUnit(descriptor.returnType!!)) "" else result)
}
//-------------------------------------------------------------------------//
fun superCall(result:String, descriptor:ClassConstructorDescriptor, args:List<LLVMValueRef?> ): LLVMValueRef? {
fun superCall(result:String, descriptor:ClassConstructorDescriptor, args:List<LLVMValueRef> ): LLVMValueRef {
val tmp = codegen.load(codegen.thisVariable(), codegen.newVar())
val rargs =
if (args.isNotEmpty())
listOf<LLVMValueRef?>(tmp, *args.toTypedArray())
else
listOf<LLVMValueRef?>(tmp)
return callDirect(descriptor, rargs!!, result)
val rargs = listOf(tmp, *args.toTypedArray())
return callDirect(descriptor, rargs, result)
}
//-------------------------------------------------------------------------//
@@ -91,10 +91,13 @@ internal fun constValue(value: LLVMValueRef?) = object : ConstValue {
override fun getLlvmValue() = value
}
internal val int8Type = LLVMInt8Type()
internal val int32Type = LLVMInt32Type()
internal val int8Type = LLVMInt8Type()!!
internal val int32Type = LLVMInt32Type()!!
internal val int8TypePtr = pointerType(int8Type)
internal fun pointerType(pointeeType: LLVMTypeRef?) = LLVMPointerType(pointeeType, 0)
internal val voidType = LLVMVoidType()
internal fun pointerType(pointeeType: LLVMTypeRef?) = LLVMPointerType(pointeeType, 0)!!
internal fun structType(vararg types: LLVMTypeRef?): LLVMTypeRef = memScoped {
LLVMStructType(allocArrayOf(*types)[0].ptr, types.size, 0)!!
@@ -127,6 +130,35 @@ internal fun CArray<CInt8Var>.getBytes(size: Long) =
(0 .. size-1).map { this[it].value }.toByteArray()
internal fun getFunctionType(ptrToFunction: LLVMValueRef?): LLVMTypeRef {
val typeOfPtrToFunction = LLVMTypeOf(ptrToFunction)
return LLVMGetElementType(typeOfPtrToFunction)!!
return getGlobalType(ptrToFunction)
}
internal fun getGlobalType(ptrToGlobal: LLVMValueRef?): LLVMTypeRef {
return LLVMGetElementType(LLVMTypeOf(ptrToGlobal))!!
}
internal fun ContextUtils.externalFunction(name: String, type: LLVMTypeRef): LLVMValueRef {
val found = LLVMGetNamedFunction(context.llvmModule, name)
if (found != null) {
assert (getFunctionType(found) == type)
return found
} else {
return LLVMAddFunction(context.llvmModule, name, type)!!
}
}
internal fun ContextUtils.externalGlobal(name: String, type: LLVMTypeRef): LLVMValueRef {
val found = LLVMGetNamedGlobal(context.llvmModule, name)
if (found != null) {
assert (getGlobalType(found) == type)
return found
} else {
return LLVMAddGlobal(context.llvmModule, type, name)!!
}
}
internal fun functionType(returnType: LLVMTypeRef?, isVarArg: Boolean = false, vararg paramTypes: LLVMTypeRef?) =
memScoped {
val paramTypesPtr = if (paramTypes.size != 0) allocArrayOf(*paramTypes)[0].ptr else null
LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, if (isVarArg) 1 else 0)!!
}
+16 -1
View File
@@ -36,10 +36,25 @@ void ThrowClassCastException() {
RuntimeAssert(false, "Throwing is unsupported");
}
class KotlinException {
public:
KRef exception_;
KotlinException(KRef exception) : exception_(exception) {
::AddRef(exception_->container());
};
~KotlinException() {
::Release(exception_->container());
};
};
void ThrowException(KRef exception) {
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
"Throwing something non-throwable");
RuntimeAssert(false, "Throwing is unsupported");
throw KotlinException(exception);
}