translator: add npe operator, exceptions emulation, fix for nulls, test
This commit is contained in:
@@ -90,7 +90,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
|||||||
fun evaluateExpression(expr: PsiElement?, scopeDepth: Int): LLVMSingleValue? {
|
fun evaluateExpression(expr: PsiElement?, scopeDepth: Int): LLVMSingleValue? {
|
||||||
return when (expr) {
|
return when (expr) {
|
||||||
is KtBlockExpression -> {
|
is KtBlockExpression -> {
|
||||||
expressionWalker(expr.firstChild, null, scopeDepth + 1)
|
expressionWalker(expr.firstChild, breakLabel = null, scopeDepth = scopeDepth + 1)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
|
is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
|
||||||
@@ -636,6 +636,18 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
|||||||
codeBuilder.storeVariable(firstOp, resultOp)
|
codeBuilder.storeVariable(firstOp, resultOp)
|
||||||
return oldValue
|
return oldValue
|
||||||
}
|
}
|
||||||
|
KtTokens.EXCLEXCL -> {
|
||||||
|
val nullLabel = codeBuilder.getNewLabel(prefix = "nullCheck")
|
||||||
|
val notNullLabel = codeBuilder.getNewLabel(prefix = "nullCheck")
|
||||||
|
val nullCheck = codeBuilder.nullCheck(firstOp)
|
||||||
|
codeBuilder.addCondition(nullCheck, nullLabel, notNullLabel)
|
||||||
|
|
||||||
|
codeBuilder.markWithLabel(nullLabel)
|
||||||
|
codeBuilder.addExceptionCall("KotlinNullPointerException")
|
||||||
|
codeBuilder.addUnconditionalJump(notNullLabel)
|
||||||
|
codeBuilder.markWithLabel(notNullLabel)
|
||||||
|
return firstOp
|
||||||
|
}
|
||||||
else -> throw UnsupportedOperationException()
|
else -> throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -895,7 +907,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
|||||||
|
|
||||||
when (expressionType) {
|
when (expressionType) {
|
||||||
is LLVMVoidType,
|
is LLVMVoidType,
|
||||||
is LLVMNullType -> {}
|
is LLVMNullType -> {
|
||||||
|
}
|
||||||
is LLVMReferenceType -> codeBuilder.allocStaticVar(resultVariable, asValue = true)
|
is LLVMReferenceType -> codeBuilder.allocStaticVar(resultVariable, asValue = true)
|
||||||
else -> codeBuilder.allocStackVar(resultVariable, asValue = true)
|
else -> codeBuilder.allocStackVar(resultVariable, asValue = true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package org.kotlinnative.translator.llvm
|
package org.kotlinnative.translator.llvm
|
||||||
|
|
||||||
import org.kotlinnative.translator.llvm.types.LLVMCharType
|
import org.kotlinnative.translator.llvm.types.*
|
||||||
import org.kotlinnative.translator.llvm.types.LLVMIntType
|
|
||||||
import org.kotlinnative.translator.llvm.types.LLVMStringType
|
|
||||||
import org.kotlinnative.translator.llvm.types.LLVMType
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class LLVMBuilder(val arm: Boolean = false) {
|
class LLVMBuilder(val arm: Boolean = false) {
|
||||||
@@ -18,22 +15,29 @@ class LLVMBuilder(val arm: Boolean = false) {
|
|||||||
initBuilder()
|
initBuilder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exceptions: Map<String, LLVMVariable> = mapOf()
|
||||||
|
|
||||||
private fun initBuilder() {
|
private fun initBuilder() {
|
||||||
val declares = arrayOf(
|
val declares = arrayOf(
|
||||||
"declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)",
|
"declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)",
|
||||||
"declare i8* @malloc_static(i32)")
|
"declare i8* @malloc_static(i32)",
|
||||||
|
"declare i32 @printf(i8*, ...)",
|
||||||
|
"declare void @abort()")
|
||||||
|
|
||||||
declares.forEach { globalCode.appendln(it) }
|
declares.forEach { globalCode.appendln(it) }
|
||||||
|
|
||||||
|
exceptions = mapOf(
|
||||||
|
Pair("KotlinNullPointerException", initializeString("Exception in thread main kotlin.KotlinNullPointerException")))
|
||||||
|
|
||||||
val funcAttributes = """attributes #0 = { nounwind "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+strict-align" }"""
|
val funcAttributes = """attributes #0 = { nounwind "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+strict-align" }"""
|
||||||
if (arm) {
|
if (arm) {
|
||||||
globalCode.appendln(funcAttributes)
|
globalCode.appendln(funcAttributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNewVariable(type: LLVMType, pointer: Int = 0, kotlinName: String? = null, scope: LLVMScope = LLVMRegisterScope()): LLVMVariable {
|
fun getNewVariable(type: LLVMType, pointer: Int = 0, kotlinName: String? = null, scope: LLVMScope = LLVMRegisterScope(), prefix: String = "var"): LLVMVariable {
|
||||||
variableCount++
|
variableCount++
|
||||||
return LLVMVariable("var$variableCount", type, kotlinName, scope, pointer)
|
return LLVMVariable("${prefix}$variableCount", type, kotlinName, scope, pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNewLabel(scope: LLVMScope = LLVMRegisterScope(), prefix: String): LLVMLabel {
|
fun getNewLabel(scope: LLVMScope = LLVMRegisterScope(), prefix: String): LLVMLabel {
|
||||||
@@ -77,9 +81,15 @@ class LLVMBuilder(val arm: Boolean = false) {
|
|||||||
localCode.appendln("ret $type $value")
|
localCode.appendln("ret $type $value")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initializeString(string: String): LLVMVariable {
|
||||||
|
val result = getNewVariable(LLVMStringType(string.length), pointer = 0, scope = LLVMVariableScope(), prefix = "exceptions.str.")
|
||||||
|
addStringConstant(result, string)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
fun addStringConstant(variable: LLVMVariable, value: String) {
|
fun addStringConstant(variable: LLVMVariable, value: String) {
|
||||||
val type = variable.type as LLVMStringType
|
val type = variable.type as LLVMStringType
|
||||||
globalCode.appendln("$variable = private unnamed_addr constant ${type.fullType()} c\"$value\\00\", align 1")
|
globalCode.appendln("$variable = private unnamed_addr constant ${type.fullType()} c\"${value.replace("\"", "\\\"")}\\00\", align 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList<LLVMVariable>, initializers: Map<LLVMVariable, String>, classType: LLVMType) {
|
fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList<LLVMVariable>, initializers: Map<LLVMVariable, String>, classType: LLVMType) {
|
||||||
@@ -121,6 +131,17 @@ class LLVMBuilder(val arm: Boolean = false) {
|
|||||||
localCode.appendln(code)
|
localCode.appendln(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun nullCheck(variable: LLVMVariable): LLVMVariable {
|
||||||
|
val result = getNewVariable(LLVMBooleanType(), pointer = 0)
|
||||||
|
|
||||||
|
val loaded = getNewVariable(variable.type, pointer = variable.pointer - 1)
|
||||||
|
loadVariable(loaded, variable)
|
||||||
|
|
||||||
|
val code = "$result = icmp eq ${loaded.getType()} null, $loaded"
|
||||||
|
localCode.appendln(code)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
fun addComment(comment: String) {
|
fun addComment(comment: String) {
|
||||||
localCode.appendln("; " + comment)
|
localCode.appendln("; " + comment)
|
||||||
}
|
}
|
||||||
@@ -218,6 +239,17 @@ class LLVMBuilder(val arm: Boolean = false) {
|
|||||||
return empty
|
return empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addExceptionCall(exceptionName: String) {
|
||||||
|
val exception = exceptions[exceptionName]
|
||||||
|
val printResult = getNewVariable(LLVMIntType(), pointer = 0)
|
||||||
|
localCode.appendln("$printResult = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds (${(exception!!.type as LLVMStringType).fullType()}* $exception, i32 0, i32 0))")
|
||||||
|
addFunctionCall(LLVMVariable("abort", LLVMVoidType(), scope = LLVMVariableScope()), emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addFunctionCall(functionName: LLVMVariable, arguments: List<LLVMVariable>) {
|
||||||
|
localCode.appendln("call ${functionName.type} $functionName(${arguments.joinToString { it -> "${it.type} $it" }})")
|
||||||
|
}
|
||||||
|
|
||||||
fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) {
|
fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) {
|
||||||
val code = "call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)"
|
val code = "call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)"
|
||||||
localCode.appendln(code)
|
localCode.appendln(code)
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
nullable_test_Int(1) == 1
|
nullable_1_test_Int(1) == 1
|
||||||
nullable_test_2_Int(4) == 5
|
nullable_1_test_2_Int(4) == 5
|
||||||
|
nullable_1_test_2_npe_operator_Int(23) == 578
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
class nullable_1_MyAwesomeClass(var i: Int)
|
||||||
|
|
||||||
class MyAwesomeClass(var i: Int)
|
fun nullable_1_test(i: Int): Int {
|
||||||
|
var x: nullable_1_MyAwesomeClass? = null
|
||||||
fun nullable_test(i: Int): Int {
|
x = nullable_1_MyAwesomeClass(i)
|
||||||
var x: MyAwesomeClass? = null
|
|
||||||
x = MyAwesomeClass(i)
|
|
||||||
return x.i
|
return x.i
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nullable_test_2(i: Int): Int {
|
fun nullable_1_test_2(i: Int): Int {
|
||||||
var x: MyAwesomeClass? = MyAwesomeClass(i)
|
var x: nullable_1_MyAwesomeClass? = nullable_1_MyAwesomeClass(i)
|
||||||
x = null
|
x = null
|
||||||
x = MyAwesomeClass(i)
|
x = nullable_1_MyAwesomeClass(i)
|
||||||
|
|
||||||
return x.i + 1
|
return x.i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nullable_1_test_2_npe_operator(i: Int): Int {
|
||||||
|
val x: nullable_1_MyAwesomeClass? = nullable_1_MyAwesomeClass(i)
|
||||||
|
x!!
|
||||||
|
return x.i + 555
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user