Support for objects' cast implemented
for code
--------8<--------
> cat ../backend.native/tests/codegen/basics/cast_simple.kt
open class A() {}
class B(): A() {}
fun castSimple(o: Any) : A = o as A
fun castTest(): Boolean {
val b = B()
castSimple(b)
return true
}
--------8<--------
translator generates
--------8<--------
>llvm-dis-mp-3.8 ../backend.native/tests/codegen/basics/cast_simple.kt.bc -o -
; ModuleID = '../backend.native/tests/codegen/basics/cast_simple.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 i8* @"kfun:castSimple(Any)"(i8*) {
entry:
%o = alloca i8*
store i8* %0, i8** %o
%tmp_1 = load i8*, i8** %o
%tmp_2 = bitcast i8* %tmp_1 to %struct.ObjHeader*
call void @CheckInstance(%struct.ObjHeader* %tmp_2, %struct.TypeInfo* @"ktype:A")
ret i8* %tmp_1
}
--------8<--------
This commit is contained in:
committed by
vvlevchenko
parent
9c28555e55
commit
3a49e69046
+2
@@ -28,6 +28,8 @@ internal class Context(val irModule: IrModuleFragment, val runtime: Runtime, val
|
|||||||
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
||||||
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
||||||
val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod")
|
val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod")
|
||||||
|
val isInstanceFunction = importRtFunction("IsInstance")
|
||||||
|
val checkInstanceFunction = importRtFunction("CheckInstance")
|
||||||
|
|
||||||
fun dispose() {
|
fun dispose() {
|
||||||
LLVMDisposeBuilder(llvmBuilder)
|
LLVMDisposeBuilder(llvmBuilder)
|
||||||
|
|||||||
+34
-6
@@ -2,9 +2,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
|
|
||||||
import kotlin_native.interop.*
|
import kotlin_native.interop.*
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.isArray
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
import org.jetbrains.kotlin.backend.konan.isInterface
|
|
||||||
import org.jetbrains.kotlin.backend.konan.isIntrinsic
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
||||||
@@ -21,6 +19,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
|
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
|
||||||
val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose
|
val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose
|
||||||
@@ -294,6 +294,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
private fun evaluateExpression(tmpVariableName: String, value: IrElement?): LLVMOpaqueValue? {
|
private fun evaluateExpression(tmpVariableName: String, value: IrElement?): LLVMOpaqueValue? {
|
||||||
when (value) {
|
when (value) {
|
||||||
is IrSetterCallImpl -> return evaluateSetterCall (tmpVariableName, value)
|
is IrSetterCallImpl -> return evaluateSetterCall (tmpVariableName, value)
|
||||||
|
is IrTypeOperatorCall-> return evaluateTypeOperator(tmpVariableName, value)
|
||||||
is IrCall -> return evaluateCall (tmpVariableName, value)
|
is IrCall -> return evaluateCall (tmpVariableName, value)
|
||||||
is IrGetValue -> return evaluateGetValue (tmpVariableName, value)
|
is IrGetValue -> return evaluateGetValue (tmpVariableName, value)
|
||||||
is IrSetVariable -> return evaluateSetVariable ( value)
|
is IrSetVariable -> return evaluateSetVariable ( value)
|
||||||
@@ -370,6 +371,32 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
return codegen.store(ret!!, variable)
|
return codegen.store(ret!!, variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
// table of conversion with llvm for primitive types
|
||||||
|
// to be used in replacement fo primitive.toX() calls with
|
||||||
|
// translator intrinsics.
|
||||||
|
// | byte short int long float double
|
||||||
|
//------------|----------------------------------------------------
|
||||||
|
// byte | x sext sext sext sitofp sitofp
|
||||||
|
// short | trunc x sext sext sitofp sitofp
|
||||||
|
// int | trunc trunc x sext sitofp sitofp
|
||||||
|
// long | trunc trunc trunc x sitofp sitofp
|
||||||
|
// float | fptosi fptosi fptosi fptosi x fpext
|
||||||
|
// double | fptosi fptosi fptosi fptosi fptrunc x
|
||||||
|
|
||||||
|
private fun evaluateTypeOperator(tmpVariableName: String, value: IrTypeOperatorCall): LLVMOpaqueValue {
|
||||||
|
logger.log("evaluateTypeOperator : ${ir2string(value)}")
|
||||||
|
assert(!KotlinBuiltIns.isPrimitiveType(value.type) && !KotlinBuiltIns.isPrimitiveType(value.argument.type))
|
||||||
|
|
||||||
|
val dstDescriptor = TypeUtils.getClassDescriptor(value.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 args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
|
||||||
|
codegen.call(context.checkInstanceFunction, args, "") // Check if dst is subclass of src.
|
||||||
|
return srcArg
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateGetField(value: IrGetField): LLVMOpaqueValue {
|
private fun evaluateGetField(value: IrGetField): LLVMOpaqueValue {
|
||||||
@@ -603,7 +630,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
isInt -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
isInt -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
||||||
else -> {
|
else -> {
|
||||||
val functions = arg0Type.memberScope.getContributedFunctions(Name.identifier("equals"), NoLookupLocation.FROM_BACKEND).filter {
|
val functions = arg0Type.memberScope.getContributedFunctions(Name.identifier("equals"), NoLookupLocation.FROM_BACKEND).filter {
|
||||||
it.valueParameters.size == 1 && KotlinBuiltIns.isAnyOrNullableAny(it.valueParameters[0].type)
|
it.valueParameters.size == 1 && KotlinBuiltIns.isNullableAny(it.valueParameters[0].type)
|
||||||
}
|
}
|
||||||
assert(functions.size == 1)
|
assert(functions.size == 1)
|
||||||
val descriptor = functions.first()
|
val descriptor = functions.first()
|
||||||
@@ -659,8 +686,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMOpaqueValue?>, result: String?): LLVMOpaqueValue? {
|
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMOpaqueValue?>, result: String?): LLVMOpaqueValue? {
|
||||||
val llvmFunction = codegen.functionLlvmValue(descriptor)
|
val realDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor)
|
||||||
return call(descriptor, llvmFunction, args, result)
|
val llvmFunction = codegen.functionLlvmValue(realDescriptor)
|
||||||
|
return codegen.call(llvmFunction, args, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ void* AllocInstance(const TypeInfo* type_info, PlacementHint hint);
|
|||||||
void* AllocArrayInstance(
|
void* AllocArrayInstance(
|
||||||
const TypeInfo* type_info, PlacementHint hint, uint32_t elements);
|
const TypeInfo* type_info, PlacementHint hint, uint32_t elements);
|
||||||
int IsInstance(const ObjHeader* obj, const TypeInfo* type_info);
|
int IsInstance(const ObjHeader* obj, const TypeInfo* type_info);
|
||||||
void CheckCast(const ObjHeader* obj, const TypeInfo* type_info);
|
void CheckInstance(const ObjHeader* obj, const TypeInfo* type_info);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user