From 4d24d735de252e16600bd6669bf6128c2e904cff Mon Sep 17 00:00:00 2001 From: Konstantin Anisimov Date: Tue, 22 Nov 2016 11:50:50 +0300 Subject: [PATCH] CODEGEN: Support for "Throw" implemented for code --------8<-------- fun main(args : Array) { val cond = 1 if (cond == 2) throw RuntimeException() if (cond == 3) throw NoSuchElementException("no such element") if (cond == 4) throw Error("error happens") println("Done") } --------8<-------- translator generates following: code --------8<-------- ; ModuleID = 'backend.native/tests/runtime/basic/throw0.kt.bc' target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" ... define void @"kfun:main(Array)"(i8*) { entry: %args = alloca i8* store i8* %0, i8** %args %cond = alloca i32 store i32 1, i32* %cond %tmp_1 = load i32, i32* %cond %tmp_0 = icmp eq i32 %tmp_1, 2 br i1 %tmp_0, label %label_1, label %label_0 label_0: ; preds = %label_1, %entry %tmp_7 = load i32, i32* %cond %tmp_6 = icmp eq i32 %tmp_7, 3 br i1 %tmp_6, label %label_3, label %label_2 label_1: ; preds = %entry %tmp_4 = call i8* @AllocInstance(%struct.TypeInfo* @"ktype:kotlin.RuntimeException", i32 1) %tmp_41 = call i8* @"kfun:kotlin.RuntimeException.()"(i8* %tmp_4) %tmp_5 = bitcast i8* %tmp_41 to %struct.ObjHeader* call void @ThrowException(%struct.ObjHeader* %tmp_5) ; <------- throwing RuntimeException br label %label_0 label_2: ; preds = %label_3, %label_0 %tmp_14 = load i32, i32* %cond %tmp_13 = icmp eq i32 %tmp_14, 4 br i1 %tmp_13, label %label_5, label %label_4 label_3: ; preds = %label_0 %tmp_10 = call i8* @AllocInstance(%struct.TypeInfo* @"ktype:kotlin.NoSuchElementException", i32 1) %tmp_102 = call i8* @"kfun:kotlin.NoSuchElementException.(String)"(i8* %tmp_10, i8* @"kstr:2E869yDM+y/5vqQYAKDPRI+j44w=") %tmp_12 = bitcast i8* %tmp_102 to %struct.ObjHeader* call void @ThrowException(%struct.ObjHeader* %tmp_12) br label %label_2 label_4: ; preds = %label_5, %label_2 call void @Kotlin_io_Console_println(i8* @"kstr:6bRQ0UvCNj0pLITxfPrVz71YpFg=") ret void label_5: ; preds = %label_2 %tmp_17 = call i8* @AllocInstance(%struct.TypeInfo* @"ktype:kotlin.Error", i32 1) %tmp_173 = call i8* @"kfun:kotlin.Error.(String)"(i8* %tmp_17, i8* @"kstr:7YdnBMJy09naL/RsuOEV6Im2kOg=") %tmp_19 = bitcast i8* %tmp_173 to %struct.ObjHeader* call void @ThrowException(%struct.ObjHeader* %tmp_19) br label %label_4 } --------8<-------- --- .../kotlin/backend/konan/llvm/CodeGenerator.kt | 1 + .../kotlin/backend/konan/llvm/Context.kt | 1 + .../kotlin/backend/konan/llvm/IrToBitcode.kt | 17 +++++++++++++++++ 3 files changed, 19 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 cb58c7d7554..7ff3dd811a3 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 @@ -164,6 +164,7 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { = LLVMPositionBuilderAtEnd(context.llvmBuilder, bbLabel) fun ret(value: LLVMOpaqueValue?) = LLVMBuildRet(context.llvmBuilder, value) + fun unreachable(): LLVMOpaqueValue? = LLVMBuildUnreachable(context.llvmBuilder) } 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 c6c61b57756..f30a7e5c03f 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 @@ -30,6 +30,7 @@ internal class Context(val irModule: IrModuleFragment, val runtime: Runtime, val val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod") val isInstanceFunction = importRtFunction("IsInstance") val checkInstanceFunction = importRtFunction("CheckInstance") + val throwExceptionFunction = importRtFunction("ThrowException") 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 4b767885513..c5516c87bc7 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 @@ -201,6 +201,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// + override fun visitThrow(expression: IrThrow) { + logger.log("visitThrow : ${ir2string(expression)}") + evaluateExpression("", expression) + } + + //-------------------------------------------------------------------------// + override fun visitFunction(declaration: IrFunction) { logger.log("visitFunction : ${ir2string(declaration)}") codegen.function(declaration) @@ -328,6 +335,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid is IrBlock -> return evaluateBlock ( value) is IrExpressionBody -> return evaluateExpression (tmpVariableName, value.expression) is IrWhen -> return evaluateWhen (tmpVariableName, value) + is IrThrow -> return evaluateThrow (tmpVariableName, value) null -> return null else -> { TODO() @@ -337,6 +345,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// + private fun evaluateThrow(tmpVariableName: String, expression: IrThrow): LLVMOpaqueValue? { + val objPointer = evaluateExpression(codegen.newVar(), expression.value) + val objHeaderPtr = codegen.bitcast(kObjHeaderPtr, objPointer!!, codegen.newVar()) + val args = listOf(objHeaderPtr) // Create arg list. + return codegen.call(context.throwExceptionFunction, args, "") + } + + //-------------------------------------------------------------------------// + private fun evaluateWhen(tmpVariableName:String, expression: IrWhen): LLVMOpaqueValue? { logger.log("evaluateWhen : ${ir2string(expression)}") var bbExit:LLVMOpaqueBasicBlock? = null // By default "when" does not have "exit".