diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt index 07ac5a3e5ad..34591d312bb 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt @@ -127,7 +127,12 @@ class IrFileImpl(entry: SourceManager.FileEntry) : IrFile { //-----------------------------------------------------------------------------// -internal interface IrPrivateFunctionCall : IrCall { +internal interface IrPrivateFunctionCall : IrExpression { + val valueArgumentsCount: Int + fun getValueArgument(index: Int): IrExpression? + fun putValueArgument(index: Int, valueArgument: IrExpression?) + fun removeValueArgument(index: Int) + val virtualCallee: IrCall? val dfgSymbol: DataFlowIR.FunctionSymbol.Declared val moduleDescriptor: ModuleDescriptor @@ -138,31 +143,47 @@ internal interface IrPrivateFunctionCall : IrCall { internal class IrPrivateFunctionCallImpl(startOffset: Int, endOffset: Int, type: IrType, - override val symbol: IrFunctionSymbol, - override val descriptor: FunctionDescriptor, + override val valueArgumentsCount: Int, override val virtualCallee: IrCall?, - typeArgumentsCount: Int, override val dfgSymbol: DataFlowIR.FunctionSymbol.Declared, override val moduleDescriptor: ModuleDescriptor, override val totalFunctions: Int, override val functionIndex: Int -) : IrPrivateFunctionCall, IrCallWithIndexedArgumentsBase( - startOffset, - endOffset, - type, - typeArgumentsCount = typeArgumentsCount, - valueArgumentsCount = symbol.descriptor.valueParameters.size -) { +) : IrPrivateFunctionCall, IrExpressionBase(startOffset, endOffset, type) { - override val superQualifierSymbol: IrClassSymbol? - get() = null + override fun accept(visitor: IrElementVisitor, data: D): R { + return visitor.visitExpression(this, data) + } - override val superQualifier: ClassDescriptor? - get() = null + private val argumentsByParameterIndex: Array = arrayOfNulls(valueArgumentsCount) - override fun accept(visitor: IrElementVisitor, data: D): R = - visitor.visitCall(this, data) + override fun getValueArgument(index: Int): IrExpression? { + if (index >= valueArgumentsCount) { + throw AssertionError("$this: No such value argument slot: $index") + } + return argumentsByParameterIndex[index] + } + override fun putValueArgument(index: Int, valueArgument: IrExpression?) { + if (index >= valueArgumentsCount) { + throw AssertionError("$this: No such value argument slot: $index") + } + argumentsByParameterIndex[index] = valueArgument + } + + override fun removeValueArgument(index: Int) { + argumentsByParameterIndex[index] = null + } + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + argumentsByParameterIndex.forEach { it?.accept(visitor, data) } + } + + override fun transformChildren(transformer: IrElementTransformer, data: D) { + argumentsByParameterIndex.forEachIndexed { i, irExpression -> + argumentsByParameterIndex[i] = irExpression?.transform(transformer, data) + } + } } internal interface IrPrivateClassReference : IrClassReference { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt index 32376ea2355..4f501562db9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt @@ -258,8 +258,8 @@ internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLV } internal fun RuntimeAware.getLlvmFunctionType(symbol: DataFlowIR.FunctionSymbol): LLVMTypeRef { - val returnType = if (symbol.returnsUnit) voidType else getLLVMType(symbol.returnType) - val paramTypes = ArrayList(symbol.parameterTypes.map { getLLVMType(it) }) + val returnType = if (symbol.returnsUnit) voidType else getLLVMType(symbol.returnParameter.type) + val paramTypes = ArrayList(symbol.parameters.map { getLLVMType(it.type) }) if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr) return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray()) 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 ba89211a33a..bcf6e4aede1 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 @@ -845,6 +845,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map return evaluateSuspendableExpression (value) is IrSuspensionPoint -> return evaluateSuspensionPoint (value) + is IrPrivateFunctionCall -> return evaluatePrivateFunctionCall (value) is IrPrivateClassReference -> return evaluatePrivateClassReference (value) else -> { @@ -2092,9 +2093,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map return evaluateOperatorCall(callee, argsWithContinuationIfNeeded) @@ -2108,7 +2106,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, resultLifetime: Lifetime): LLVMValueRef { + private fun evaluatePrivateFunctionCall(callee: IrPrivateFunctionCall): LLVMValueRef { + val args = (0 until callee.valueArgumentsCount).map { index -> + callee.getValueArgument(index)?.let { evaluateExpression(it) } + ?: run { + assert(index == callee.valueArgumentsCount - 1) { "Only last argument may be null - for suspend functions" } + getContinuation() + } + } val dfgSymbol = callee.dfgSymbol val functionIndex = callee.functionIndex val function = if (callee.moduleDescriptor == context.irModule!!.descriptor) { @@ -2121,7 +2126,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, + resultLifetime: Lifetime): LLVMValueRef { + val result = call(function, args, resultLifetime) + if (symbol.returnsNothing) { + functionGenerationContext.unreachable() + } + + if (LLVMGetReturnType(getFunctionType(function)) == voidType) { + return codegen.theUnitInstanceRef.llvm + } + + return result + } + private fun call(function: LLVMValueRef, args: List, resultLifetime: Lifetime = Lifetime.IRRELEVANT): LLVMValueRef { return functionGenerationContext.call(function, args, resultLifetime, currentCodeContext.exceptionHandler) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt index 207df900f40..7357e0cae67 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt @@ -300,13 +300,26 @@ internal object DFGSerializer { } } - class FunctionSymbolBase(val parameterTypes: IntArray, val returnType: Int, val attributes: Int, val escapes: Int?, val pointsTo: IntArray?) { + class FunctionParameter(val type: Int, val boxFunction: Int?, val unboxFunction: Int?) { - constructor(data: ArraySlice) : this(data.readIntArray(), data.readInt(), data.readInt(), data.readNullableInt(), data.readNullable { readIntArray() }) + constructor(data: ArraySlice) : this(data.readInt(), data.readNullableInt(), data.readNullableInt()) fun write(result: ArraySlice) { - result.writeIntArray(parameterTypes) - result.writeInt(returnType) + result.writeInt(type) + result.writeNullableInt(boxFunction) + result.writeNullableInt(unboxFunction) + } + } + + class FunctionSymbolBase(val parameters: Array, val returnParameter: FunctionParameter, + val attributes: Int, val escapes: Int?, val pointsTo: IntArray?) { + + constructor(data: ArraySlice) : this(data.readArray { FunctionParameter(data) }, FunctionParameter(data), data.readInt(), + data.readNullableInt(), data.readNullable { readIntArray() }) + + fun write(result: ArraySlice) { + result.writeArray(parameters) { it.write(this) } + returnParameter.write(result) result.writeInt(attributes) result.writeNullableInt(escapes) result.writeNullable(pointsTo) { writeIntArray(it) } @@ -814,10 +827,14 @@ internal object DFGSerializer { .sortedBy { it.value } .map { + fun buildFunctionParameter(parameter: DataFlowIR.FunctionParameter) = + FunctionParameter(typeMap[parameter.type]!!, parameter.boxFunction?.let { functionSymbolMap[it]!! }, + parameter.unboxFunction?.let { functionSymbolMap[it]!! }) + fun buildFunctionSymbolBase(symbol: DataFlowIR.FunctionSymbol) = FunctionSymbolBase( - symbol.parameterTypes.map { typeMap[it]!! }.toIntArray(), - typeMap[symbol.returnType]!!, + symbol.parameters.map { buildFunctionParameter(it) }.toTypedArray(), + buildFunctionParameter(symbol.returnParameter), symbol.attributes, symbol.escapes, symbol.pointsTo @@ -1016,8 +1033,6 @@ internal object DFGSerializer { module, symbolTableIndex, attributes, null, private.name) } }.apply { - parameterTypes = it.base.parameterTypes.map { types[it] }.toTypedArray() - returnType = types[it.base.returnType] escapes = it.base.escapes pointsTo = it.base.pointsTo } @@ -1043,9 +1058,15 @@ internal object DFGSerializer { } } + fun buildFunctionParameter(parameter: FunctionParameter) = + DataFlowIR.FunctionParameter(types[parameter.type], parameter.boxFunction?.let { functionSymbols[it] }, + parameter.unboxFunction?.let { functionSymbols[it] }) + symbolTable.functionSymbols.forEachIndexed { index, symbol -> - val deserializedSymbol = functionSymbols[index] as? DataFlowIR.FunctionSymbol.Declared - ?: return@forEachIndexed + val deserializedSymbol = functionSymbols[index] + deserializedSymbol.parameters = symbol.base.parameters.map { buildFunctionParameter(it) }.toTypedArray() + deserializedSymbol.returnParameter = buildFunctionParameter(symbol.base.returnParameter) + deserializedSymbol as? DataFlowIR.FunctionSymbol.Declared ?: return@forEachIndexed val bridgeTarget = if (deserializedSymbol is DataFlowIR.FunctionSymbol.Public) symbol.public!!.bridgeTarget else diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt index 2fb16fa8701..6d1f258e9f7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt @@ -121,9 +121,11 @@ internal object DataFlowIR { val RETURNS_NOTHING = 4 } + class FunctionParameter(val type: Type, val boxFunction: FunctionSymbol?, val unboxFunction: FunctionSymbol?) + abstract class FunctionSymbol(val attributes: Int, val name: String?) { - lateinit var parameterTypes: Array - lateinit var returnType: Type + lateinit var parameters: Array + lateinit var returnParameter: FunctionParameter val isGlobalInitializer = attributes.and(FunctionAttributes.IS_GLOBAL_INITIALIZER) != 0 val returnsUnit = attributes.and(FunctionAttributes.RETURNS_UNIT) != 0 @@ -266,7 +268,7 @@ internal object DataFlowIR { fun debugOutput() { println("FUNCTION $symbol") - println("Params: ${symbol.parameterTypes.contentToString()}") + println("Params: ${symbol.parameters.contentToString()}") val ids = body.nodes.withIndex().associateBy({ it.value }, { it.index }) body.nodes.forEach { println(" NODE #${ids[it]!!}") @@ -555,6 +557,12 @@ internal object DataFlowIR { } } + private fun mapTypeToFunctionParameter(type: IrType) = + type.getInlinedClass().let { inlinedClass -> + FunctionParameter(mapType(type), inlinedClass?.let { mapFunction(context.getBoxFunction(it)) }, + inlinedClass?.let { mapFunction(context.getUnboxFunction(it)) }) + } + // TODO: use from LlvmDeclarations. private fun getFqName(descriptor: DeclarationDescriptor): FqName = descriptor.parent.fqNameSafe.child(descriptor.name) @@ -602,7 +610,7 @@ internal object DataFlowIR { val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget) val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null && !classDescriptor.isNonGeneratedAnnotation() - && (it.isOverridableOrOverrides || bridgeTarget != null || descriptor.name.asString().contains("") || it.contains("") } + private fun mapPropertyInitializer(descriptor: IrField): FunctionSymbol = descriptor.original.let { functionMap[it]?.let { return it } @@ -633,8 +644,8 @@ internal object DataFlowIR { functionMap[it] = symbol - symbol.parameterTypes = emptyArray() - symbol.returnType = mapClassReferenceType(context.ir.symbols.unit.owner) + symbol.parameters = emptyArray() + symbol.returnParameter = mapTypeToFunctionParameter(context.irBuiltIns.unitType) return symbol } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt index 1e245d0e534..ddfbf31aaba 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt @@ -27,9 +27,6 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.getValueArgument import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl import org.jetbrains.kotlin.ir.expressions.impl.IrWhenImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol @@ -236,8 +233,8 @@ internal object Devirtualization { // Rapid Type Analysis: find all instantiations and conservatively estimate call graph. // Add all final parameters of the roots. rootSet.forEach { - it.parameterTypes - .map { it.resolved() } + it.parameters + .map { it.type.resolved() } .filter { it.isFinal } .forEach { addInstantiatingClass(it) } } @@ -323,7 +320,7 @@ internal object Devirtualization { DEBUG_OUTPUT(1) { println("Function $resolvedFunctionSymbol is external") } - val resolvedReturnType = symbol.returnType.resolved() + val resolvedReturnType = symbol.returnParameter.type.resolved() if (resolvedReturnType.isFinal) { DEBUG_OUTPUT(1) { println("Adding return type as it is final") } @@ -373,7 +370,7 @@ internal object Devirtualization { if (node.receiverType == DataFlowIR.Type.Virtual) continue@nodeLoop val receiverType = node.receiverType.resolved() - val vCallReturnType = node.callee.returnType.resolved() + val vCallReturnType = node.callee.returnParameter.type.resolved() DEBUG_OUTPUT(1) { println("Adding virtual callsite:") @@ -737,11 +734,11 @@ internal object Devirtualization { if (symbol is DataFlowIR.FunctionSymbol.External) return null constraintGraph.functions[symbol]?.let { return it } - val parameters = Array(symbol.parameterTypes.size) { ordinaryNode { "Param#$it\$$symbol" } } + val parameters = Array(symbol.parameters.size) { ordinaryNode { "Param#$it\$$symbol" } } if (isRoot) { // Exported function from the current module. - symbol.parameterTypes.forEachIndexed { index, type -> - val resolvedType = type.resolved() + symbol.parameters.forEachIndexed { index, type -> + val resolvedType = type.type.resolved() val node = if (!resolvedType.isFinal) constraintGraph.virtualNode else @@ -858,7 +855,7 @@ internal object Devirtualization { function.parameters[node.index] is DataFlowIR.Node.StaticCall -> - doCall(node.callee, node.arguments, node.callee.returnType.resolved(), node.receiverType?.resolved()) + doCall(node.callee, node.arguments, node.callee.returnParameter.type.resolved(), node.receiverType?.resolved()) is DataFlowIR.Node.NewObject -> { val returnType = node.constructedType.resolved() @@ -901,7 +898,7 @@ internal object Devirtualization { println() } - val returnType = node.callee.returnType.resolved() + val returnType = node.callee.returnParameter.type.resolved() val receiverNode = edgeToConstraintNode(node.arguments[0]) if (receiverType == DataFlowIR.Type.Virtual) constraintGraph.virtualNode.addEdge(receiverNode) @@ -1001,13 +998,8 @@ internal object Devirtualization { private fun devirtualize(irModule: IrModuleFragment, context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG, devirtualizedCallSites: Map) { - val nativePtrType = context.ir.symbols.nativePtrType val nativePtrEqualityOperatorSymbol = context.ir.symbols.areEqualByValue[PrimitiveBinaryType.POINTER]!! val optimize = context.shouldOptimize() - /* - val boxFunctions = ValueType.values().associate { context.ir.symbols.boxFunctions[it]!! to it } - val unboxFunctions = ValueType.values().associate { context.ir.symbols.getUnboxFunction(it) to it } - */ fun DataFlowIR.Type.resolved(): DataFlowIR.Type.Declared { if (this is DataFlowIR.Type.Declared) return this @@ -1021,11 +1013,8 @@ internal object Devirtualization { return this } - /* - fun IrExpression.isBoxOrUnboxCall() = this is IrCall && (boxFunctions[symbol] != null || unboxFunctions[symbol] != null) - */ - - fun IrExpression.isBoxOrUnboxCall() = false + // TODO: do it more reliably. + fun IrExpression.isBoxOrUnboxCall() = this is IrCall && symbol.owner.name.asString().let { it.contains("") || it.contains("") } fun IrBuilderWithScope.irCoerce(value: IrExpression, coercion: IrFunctionSymbol?) = if (coercion == null) @@ -1034,6 +1023,23 @@ internal object Devirtualization { addArguments(listOf(coercion.descriptor.explicitParameters.single() to value)) } + fun IrBuilderWithScope.irCoerce(value: IrExpression, coercion: DataFlowIR.FunctionSymbol.Declared?) = + if (coercion == null) + value + else IrPrivateFunctionCallImpl( + startOffset = startOffset, + endOffset = endOffset, + type = value.type, // TODO: What type is actually must be here? + valueArgumentsCount = 1, + virtualCallee = null, + dfgSymbol = coercion, + moduleDescriptor = coercion.module.descriptor, + totalFunctions = coercion.module.numberOfFunctions, + functionIndex = coercion.symbolTableIndex + ).apply { + putValueArgument(0, value) + } + class PossiblyCoercedValue(val value: IrVariable, val coercion: IrFunctionSymbol?) { fun getFullValue(irBuilder: IrBuilderWithScope) = irBuilder.run { irCoerce(irGet(value), coercion) @@ -1065,89 +1071,74 @@ internal object Devirtualization { , coercion.symbol) } - /* - fun assertCoercionsMatch(coercion1: IrFunctionSymbol, coercion2: IrFunctionSymbol) { - boxFunctions[coercion1]?.let { assert (unboxFunctions[coercion2] == it) - { "Incosistent coercions: ${coercion1.descriptor}, ${coercion2.descriptor}" } - } - unboxFunctions[coercion1]?.let { assert (boxFunctions[coercion2] == it) - { "Incosistent coercions: ${coercion1.descriptor}, ${coercion2.descriptor}" } + class CoercionPair(val coerceFunction: DataFlowIR.FunctionSymbol.Declared, val uncoerceFunction: DataFlowIR.FunctionSymbol.Declared) + + fun getTypeConversion(actualType: DataFlowIR.FunctionParameter, targetType: DataFlowIR.FunctionParameter): CoercionPair? { + if (actualType.boxFunction == null && targetType.boxFunction == null) return null + if (actualType.boxFunction != null && targetType.boxFunction != null) { + assert (actualType.type.resolved() == targetType.type.resolved()) + { "Inconsistent types: ${actualType.type} and ${targetType.type}" } + return null } + if (actualType.boxFunction == null) + return CoercionPair(targetType.unboxFunction!!.resolved() as DataFlowIR.FunctionSymbol.Declared, + targetType.boxFunction!!.resolved() as DataFlowIR.FunctionSymbol.Declared) + return CoercionPair(actualType.boxFunction!!.resolved() as DataFlowIR.FunctionSymbol.Declared, + actualType.unboxFunction!!.resolved() as DataFlowIR.FunctionSymbol.Declared) } - fun IrBuilderWithScope.irCoerceIfNeeded(type: DataFlowIR.Type.Declared, targetType: DataFlowIR.Type.Declared, + fun IrBuilderWithScope.irCoerceIfNeeded(type: DataFlowIR.FunctionParameter, targetType: DataFlowIR.FunctionParameter, possiblyCoercedValue: PossiblyCoercedValue): IrExpression { val value = possiblyCoercedValue.value val prevCoercion = possiblyCoercedValue.coercion - val coercion = context.ir.symbols.getTypeConversion(type.correspondingValueType, targetType.correspondingValueType) + val coercion = getTypeConversion(type, targetType) ?: return possiblyCoercedValue.getFullValue(this) if (prevCoercion == null) - return irCoerce(irGet(value), coercion) - assertCoercionsMatch(coercion, prevCoercion) + return irCoerce(irGet(value), coercion.coerceFunction) + val expectedUncoercion = coercion.uncoerceFunction + val actualUncoercion = moduleDFG.symbolTable.mapFunction(prevCoercion.owner).resolved() + assert(actualUncoercion == expectedUncoercion) { "Incosistent coercions: ${expectedUncoercion}, ${actualUncoercion}" } return irGet(value) } - */ - fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: IrType, - devirtualizedCallee: DataFlowIR.FunctionSymbol.Declared) = + fun irDevirtualizedCall(callee: IrCall, actualType: IrType, devirtualizedCallee: DataFlowIR.FunctionSymbol.Declared) = IrPrivateFunctionCallImpl( - startOffset = startOffset, - endOffset = endOffset, - type = actualType, - symbol = callee.symbol, - descriptor = callee.descriptor, - typeArgumentsCount = callee.typeArgumentsCount, - dfgSymbol = devirtualizedCallee, - totalFunctions = devirtualizedCallee.module.numberOfFunctions, - moduleDescriptor = devirtualizedCallee.module.descriptor, - functionIndex = devirtualizedCallee.symbolTableIndex, - virtualCallee = callee + startOffset = callee.startOffset, + endOffset = callee.endOffset, + type = actualType, + valueArgumentsCount = devirtualizedCallee.parameters.size, + virtualCallee = callee, + dfgSymbol = devirtualizedCallee, + moduleDescriptor = devirtualizedCallee.module.descriptor, + totalFunctions = devirtualizedCallee.module.numberOfFunctions, + functionIndex = devirtualizedCallee.symbolTableIndex ) fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: IrType, - actualCallee: DataFlowIR.FunctionSymbol.Declared, - receiver: IrVariable, - extensionReceiver: PossiblyCoercedValue?, - parameters: Map) = + actualCallee: DataFlowIR.FunctionSymbol.Declared, + parameters: List) = actualCallee.bridgeTarget.let { -// if (it == null) + if (it == null) irDevirtualizedCall(callee, actualType, actualCallee).apply { - this.dispatchReceiver = irGet(receiver) - this.extensionReceiver = extensionReceiver?.getFullValue(this@irDevirtualizedCall) - callee.descriptor.valueParameters.forEach { - putValueArgument(it.index, parameters[it]!!.getFullValue(this@irDevirtualizedCall)) + parameters.forEachIndexed { index, value -> + putValueArgument(index, value.getFullValue(this@irDevirtualizedCall)) } } - /* else { val bridgeTarget = it.resolved() as DataFlowIR.FunctionSymbol.Declared val callResult = irDevirtualizedCall(callee, actualType, bridgeTarget).apply { - this.dispatchReceiver = irGet(receiver) - this.extensionReceiver = extensionReceiver?.let { - irCoerceIfNeeded( - type = actualCallee.parameterTypes[1].resolved(), - targetType = bridgeTarget.parameterTypes[1].resolved(), - possiblyCoercedValue = it - ) - } - val startIndex = if (extensionReceiver == null) 1 else 2 - callee.descriptor.valueParameters.forEach { - this.putValueArgument(it.index, - irCoerceIfNeeded( - type = actualCallee.parameterTypes[startIndex + it.index].resolved(), - targetType = bridgeTarget.parameterTypes[startIndex + it.index].resolved(), - possiblyCoercedValue = parameters[it]!! - ) - ) + parameters.forEachIndexed { index, value -> + putValueArgument(index, irCoerceIfNeeded( + type = actualCallee.parameters[index], + targetType = bridgeTarget.parameters[index], + possiblyCoercedValue = value + )) } } - val returnCoercion = context.ir.symbols.getTypeConversion( - bridgeTarget.returnType.resolved().correspondingValueType, - actualCallee.returnType.resolved().correspondingValueType) - irCoerce(callResult, returnCoercion) + val returnCoercion = getTypeConversion(bridgeTarget.returnParameter, actualCallee.returnParameter) + irCoerce(callResult, returnCoercion?.coerceFunction) } - */ } irModule.transformChildrenVoid(object: IrElementTransformerVoidWithContext() { @@ -1160,12 +1151,10 @@ internal object Devirtualization { arg.argument else arg if (!uncastedArg.isBoxOrUnboxCall()) return expression - /* val argarg = (uncastedArg as IrCall).getArguments().single().second - if (boxFunctions[expression.symbol].let { it != null && it == unboxFunctions[uncastedArg.symbol] } - || unboxFunctions[expression.symbol].let { it != null && it == boxFunctions[uncastedArg.symbol] }) + if (expression.symbol.owner.returnType == uncastedArg.symbol.owner.explicitParameters.single().type + && expression.symbol.owner.explicitParameters.single().type == uncastedArg.symbol.owner.returnType) return argarg - */ return expression } @@ -1209,27 +1198,19 @@ internal object Devirtualization { optimize && possibleCallees.size == 1 -> { // Monomorphic callsite. val actualCallee = possibleCallees[0].callee as DataFlowIR.FunctionSymbol.Declared irBlock(expression) { - val receiver = irTemporary(dispatchReceiver, "receiver") - val extensionReceiver = expression.extensionReceiver?.let { - irSplitCoercion(it, "extensionReceiver", function.extensionReceiverParameter!!.type) + val parameters = expression.getArgumentsWithSymbols().mapIndexed { index, arg -> + irSplitCoercion(arg.second, "arg$index", arg.first.owner.type) } - val parameters = expression.descriptor.valueParameters.associate { - it to irSplitCoercion(expression.getValueArgument(it)!!, "arg${it.index}", function.valueParameters[it.index].type) - } - +irDevirtualizedCall(expression, type, actualCallee, receiver, extensionReceiver, parameters) + +irDevirtualizedCall(expression, type, actualCallee, parameters) } } else -> irBlock(expression) { - val receiver = irTemporary(dispatchReceiver, "receiver") - val extensionReceiver = expression.extensionReceiver?.let { - irSplitCoercion(it, "extensionReceiver", function.extensionReceiverParameter!!.type) - } - val parameters = expression.descriptor.valueParameters.associate { - it to irSplitCoercion(expression.getValueArgument(it)!!, "arg${it.index}", function.valueParameters[it.index].type) + val parameters = expression.getArgumentsWithSymbols().mapIndexed { index, arg -> + irSplitCoercion(arg.second, "arg$index", arg.first.owner.type) } val typeInfo = irTemporary(irCall(context.ir.symbols.getObjectTypeInfo).apply { - putValueArgument(0, irGet(receiver)) + putValueArgument(0, parameters[0].getFullValue(this@irBlock)) }) val branches = mutableListOf() @@ -1241,7 +1222,7 @@ internal object Devirtualization { endOffset = endOffset, type = context.ir.symbols.nativePtrType, symbol = dispatchReceiver.type.getErasedTypeClass(), - classType = receiver.type, + classType = dispatchReceiver.type, moduleDescriptor = actualReceiverType.module!!.descriptor, totalClasses = actualReceiverType.module.numberOfClasses, classIndex = actualReceiverType.symbolTableIndex, @@ -1258,7 +1239,7 @@ internal object Devirtualization { startOffset = startOffset, endOffset = endOffset, condition = condition, - result = irDevirtualizedCall(expression, type, actualCallee, receiver, extensionReceiver, parameters) + result = irDevirtualizedCall(expression, type, actualCallee, parameters) ) } if (!optimize) { // Add else branch throwing exception for debug purposes. diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt index 370e3137eb7..6d0072cebd3 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.konan.DirectedGraphMultiNode import org.jetbrains.kotlin.backend.konan.llvm.Lifetime import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.ir.util.defaultType internal object EscapeAnalysis { @@ -283,7 +282,7 @@ internal object EscapeAnalysis { } for (functionSymbol in callGraph.directEdges.keys) { - val numberOfParameters = functionSymbol.parameterTypes.size + val numberOfParameters = functionSymbol.parameters.size escapeAnalysisResults[functionSymbol] = FunctionEscapeAnalysisResult( // Assume no edges at the beginning. // Then iteratively add needed. @@ -396,7 +395,7 @@ internal object EscapeAnalysis { } private fun getConservativeFunctionEAResult(symbol: DataFlowIR.FunctionSymbol): FunctionEscapeAnalysisResult { - val numberOfParameters = symbol.parameterTypes.size + val numberOfParameters = symbol.parameters.size return FunctionEscapeAnalysisResult((0..numberOfParameters).map { ParameterEscapeAnalysisResult( escapes = true, @@ -425,7 +424,7 @@ internal object EscapeAnalysis { FunctionEscapeAnalysisResult.fromBits( callee.escapes ?: 0, - (0..callee.parameterTypes.size).map { callee.pointsTo?.elementAtOrNull(it) ?: 0 } + (0..callee.parameters.size).map { callee.pointsTo?.elementAtOrNull(it) ?: 0 } ) }