[K/N] Added isSubtype intrinsic
This commit is contained in:
+2
@@ -354,6 +354,8 @@ internal class KonanSymbols(
|
||||
|
||||
val initInstance = internalFunction("initInstance")
|
||||
|
||||
val isSubtype = internalFunction("isSubtype")
|
||||
|
||||
val println = irBuiltIns.findFunctions(Name.identifier("println"), "kotlin", "io")
|
||||
.single { lookup.getValueParametersCount(it) == 1 && lookup.isValueParameterClass(it, 0, string) }
|
||||
|
||||
|
||||
+16
-2
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Runnable
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.konan.ForeignExceptionMode
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
@@ -213,7 +212,7 @@ private fun IrSimpleFunction.findOverriddenMethodOfAny(): IrSimpleFunction? {
|
||||
}
|
||||
|
||||
internal object VirtualTablesLookup {
|
||||
fun FunctionGenerationContext.getInterfaceTableRecord(typeInfo: LLVMValueRef, interfaceId: Int): LLVMValueRef {
|
||||
private fun FunctionGenerationContext.getInterfaceTableRecord(typeInfo: LLVMValueRef, interfaceId: Int): LLVMValueRef {
|
||||
val interfaceTableSize = load(structGep(typeInfo, 9 /* interfaceTableSize_ */))
|
||||
val interfaceTable = load(structGep(typeInfo, 10 /* interfaceTable_ */))
|
||||
|
||||
@@ -254,6 +253,21 @@ internal object VirtualTablesLookup {
|
||||
}
|
||||
}
|
||||
|
||||
fun FunctionGenerationContext.checkIsSubtype(objTypeInfo: LLVMValueRef, dstClass: IrClass) = if (!context.ghaEnabled()) {
|
||||
call(llvm.isSubtypeFunction, listOf(objTypeInfo, codegen.typeInfoValue(dstClass)))
|
||||
} else {
|
||||
val dstHierarchyInfo = context.getLayoutBuilder(dstClass).hierarchyInfo
|
||||
if (!dstClass.isInterface) {
|
||||
call(llvm.isSubclassFastFunction,
|
||||
listOf(objTypeInfo, llvm.int32(dstHierarchyInfo.classIdLo), llvm.int32(dstHierarchyInfo.classIdHi)))
|
||||
} else {
|
||||
// Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId
|
||||
val interfaceId = dstHierarchyInfo.interfaceId
|
||||
val interfaceTableRecord = getInterfaceTableRecord(objTypeInfo, interfaceId)
|
||||
icmpEq(load(structGep(interfaceTableRecord, 0 /* id */)), llvm.int32(interfaceId))
|
||||
}
|
||||
}
|
||||
|
||||
fun FunctionGenerationContext.getVirtualImpl(receiver: LLVMValueRef, irFunction: IrSimpleFunction): LlvmCallable {
|
||||
assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr)
|
||||
|
||||
|
||||
+2
-2
@@ -426,8 +426,8 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
|
||||
val setCurrentFrameFunction = importRtFunction("SetCurrentFrame")
|
||||
val checkCurrentFrameFunction = importRtFunction("CheckCurrentFrame")
|
||||
val lookupInterfaceTableRecord = importRtFunction("LookupInterfaceTableRecord")
|
||||
val isInstanceFunction = importRtFunction("IsInstance")
|
||||
val isInstanceOfClassFastFunction = importRtFunction("IsInstanceOfClassFast")
|
||||
val isSubtypeFunction = importRtFunction("IsSubtype")
|
||||
val isSubclassFastFunction = importRtFunction("IsSubclassFast")
|
||||
val throwExceptionFunction = importRtFunction("ThrowException")
|
||||
val appendToInitalizersTail = importRtFunction("AppendToInitializersTail")
|
||||
val callInitGlobalPossiblyLock = importRtFunction("CallInitGlobalPossiblyLock")
|
||||
|
||||
+11
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.util.findAnnotation
|
||||
|
||||
@@ -65,6 +66,7 @@ internal enum class IntrinsicType {
|
||||
IDENTITY,
|
||||
IMMUTABLE_BLOB,
|
||||
INIT_INSTANCE,
|
||||
IS_SUBTYPE,
|
||||
IS_EXPERIMENTAL_MM,
|
||||
THE_UNIT_INSTANCE,
|
||||
// Enums
|
||||
@@ -247,6 +249,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
IntrinsicType.INTEROP_WRITE_PRIMITIVE -> emitWritePrimitive(callSite, args)
|
||||
IntrinsicType.INTEROP_GET_POINTER_SIZE -> emitGetPointerSize()
|
||||
IntrinsicType.CREATE_UNINITIALIZED_INSTANCE -> emitCreateUninitializedInstance(callSite, resultSlot)
|
||||
IntrinsicType.IS_SUBTYPE -> emitIsSubtype(callSite, args)
|
||||
IntrinsicType.INTEROP_NATIVE_PTR_TO_LONG -> emitNativePtrToLong(callSite, args)
|
||||
IntrinsicType.INTEROP_NATIVE_PTR_PLUS_LONG -> emitNativePtrPlusLong(args)
|
||||
IntrinsicType.INTEROP_GET_NATIVE_NULL_PTR -> emitGetNativeNullPtr()
|
||||
@@ -419,6 +422,14 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
return allocInstance(enumIrClass, environment.calculateLifetime(callSite), resultSlot)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitIsSubtype(callSite: IrCall, args: List<LLVMValueRef>) =
|
||||
with(VirtualTablesLookup) {
|
||||
checkIsSubtype(
|
||||
objTypeInfo = bitcast(pointerType(llvm.kTypeInfo), args.single()),
|
||||
dstClass = callSite.getTypeArgument(0)!!.classOrNull!!.owner
|
||||
)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetPointerSize(): LLVMValueRef =
|
||||
llvm.int32(LLVMPointerSize(codegen.llvmTargetData))
|
||||
|
||||
|
||||
+7
-23
@@ -1585,30 +1585,14 @@ internal class CodeGeneratorVisitor(
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun genInstanceOf(obj: LLVMValueRef, dstClass: IrClass): LLVMValueRef {
|
||||
private fun genInstanceOf(obj: LLVMValueRef, dstClass: IrClass) = with(functionGenerationContext) {
|
||||
if (dstClass.defaultType.isObjCObjectType()) {
|
||||
return genInstanceOfObjC(obj, dstClass)
|
||||
}
|
||||
|
||||
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj)
|
||||
|
||||
return if (!context.ghaEnabled()) {
|
||||
call(llvm.isInstanceFunction, listOf(srcObjInfoPtr, codegen.typeInfoValue(dstClass)))
|
||||
} else {
|
||||
val dstHierarchyInfo = context.getLayoutBuilder(dstClass).hierarchyInfo
|
||||
if (!dstClass.isInterface) {
|
||||
call(llvm.isInstanceOfClassFastFunction,
|
||||
listOf(srcObjInfoPtr, llvm.int32(dstHierarchyInfo.classIdLo), llvm.int32(dstHierarchyInfo.classIdHi)))
|
||||
} else {
|
||||
// Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId
|
||||
val interfaceId = dstHierarchyInfo.interfaceId
|
||||
val typeInfo = functionGenerationContext.loadTypeInfo(srcObjInfoPtr)
|
||||
with(functionGenerationContext) {
|
||||
|
||||
val interfaceTableRecord = with(VirtualTablesLookup) { getInterfaceTableRecord(typeInfo, interfaceId) }
|
||||
icmpEq(load(structGep(interfaceTableRecord, 0 /* id */)), llvm.int32(interfaceId))
|
||||
}
|
||||
}
|
||||
genInstanceOfObjC(obj, dstClass)
|
||||
} else with(VirtualTablesLookup) {
|
||||
checkIsSubtype(
|
||||
objTypeInfo = loadTypeInfo(bitcast(codegen.kObjHeaderPtr, obj)),
|
||||
dstClass
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-9
@@ -1361,8 +1361,8 @@ internal object DevirtualizationAnalysis {
|
||||
fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
|
||||
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
|
||||
val symbols = context.ir.symbols
|
||||
val irBuiltIns = context.irBuiltIns
|
||||
val nativePtrEqualityOperatorSymbol = symbols.areEqualByValue[PrimitiveBinaryType.POINTER]!!
|
||||
val isSubtype = symbols.isSubtype
|
||||
val optimize = context.shouldOptimize()
|
||||
|
||||
fun DataFlowIR.Type.resolved(): DataFlowIR.Type.Declared {
|
||||
@@ -1582,14 +1582,9 @@ internal object DevirtualizationAnalysis {
|
||||
}
|
||||
} else {
|
||||
val receiverType = actualCallee.irFunction!!.parentAsClass
|
||||
IrTypeOperatorCallImpl(
|
||||
startOffset = startOffset,
|
||||
endOffset = endOffset,
|
||||
type = irBuiltIns.booleanType,
|
||||
operator = IrTypeOperator.INSTANCEOF,
|
||||
typeOperand = receiverType.defaultType,
|
||||
argument = irGet(receiver)
|
||||
)
|
||||
irCall(isSubtype, listOf(receiverType.defaultType)).apply {
|
||||
putValueArgument(0, irGet(typeInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
IrBranchImpl(
|
||||
|
||||
Reference in New Issue
Block a user