Turned on bridges inlining

This commit is contained in:
Igor Chevdar
2018-09-17 19:06:34 +03:00
parent 973cc7bbdb
commit 2065b79a7b
7 changed files with 206 additions and 149 deletions
@@ -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 <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitExpression(this, data)
}
override val superQualifier: ClassDescriptor?
get() = null
private val argumentsByParameterIndex: Array<IrExpression?> = arrayOfNulls(valueArgumentsCount)
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, 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 <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
argumentsByParameterIndex.forEach { it?.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
argumentsByParameterIndex.forEachIndexed { i, irExpression ->
argumentsByParameterIndex[i] = irExpression?.transform(transformer, data)
}
}
}
internal interface IrPrivateClassReference : IrClassReference {
@@ -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())
@@ -845,6 +845,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrSuspendableExpression ->
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<IrE
return evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
}
if (callee is IrPrivateFunctionCall)
return evaluatePrivateFunctionCall(callee, argsWithContinuationIfNeeded, callee.virtualCallee?.let { resultLifetime(it) } ?: resultLifetime)
when {
descriptor.origin == IrDeclarationOrigin.IR_BUILTINS_STUB ->
return evaluateOperatorCall(callee, argsWithContinuationIfNeeded)
@@ -2108,7 +2106,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluatePrivateFunctionCall(callee: IrPrivateFunctionCall, args: List<LLVMValueRef>, 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<IrE
)
}
return call(callee.symbol.owner, function, args, resultLifetime)
return call(dfgSymbol, function, args, resultLifetime = Lifetime.GLOBAL)
}
//-------------------------------------------------------------------------//
@@ -2567,6 +2572,25 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return result
}
// TODO: it seems to be much more reliable to get args as a mapping from parameter descriptor to LLVM value,
// instead of a plain list.
// In such case it would be possible to check that all args are available and in the correct order.
// However, it currently requires some refactoring to be performed.
private fun call(symbol: DataFlowIR.FunctionSymbol, function: LLVMValueRef, args: List<LLVMValueRef>,
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<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT): LLVMValueRef {
return functionGenerationContext.call(function, args, resultLifetime, currentCodeContext.exceptionHandler)
@@ -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<FunctionParameter>, 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
@@ -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<Type>
lateinit var returnType: Type
lateinit var parameters: Array<FunctionParameter>
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("<bridge-") || !classDescriptor.isFinal())
&& (it.isOverridableOrOverrides || bridgeTarget != null || descriptor.isSpecial || !classDescriptor.isFinal())
val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1
if (it.isExported())
FunctionSymbol.Public(name.localHash.value, module, symbolTableIndex, attributes, bridgeTargetSymbol, takeName { name })
@@ -612,18 +620,21 @@ internal object DataFlowIR {
}
functionMap[it] = symbol
symbol.parameterTypes =
symbol.parameters =
(descriptor.allParameters.map { it.type } + (if (descriptor.isSuspend) listOf(continuationType) else emptyList()))
.map { mapType(it) }
.map { mapTypeToFunctionParameter(it) }
.toTypedArray()
symbol.returnType = mapType(if (descriptor.isSuspend)
context.irBuiltIns.anyType
else
descriptor.returnType)
symbol.returnParameter = mapTypeToFunctionParameter(if (descriptor.isSuspend)
context.irBuiltIns.anyType
else
descriptor.returnType)
return symbol
}
private val FunctionDescriptor.isSpecial get() =
name.asString().let { it.contains("<bridge-") || it.contains("<box>") || it.contains("<unbox>") }
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
}
@@ -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<IrCall, DevirtualizedCallSite>) {
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("<box>") || it.contains("<unbox>") }
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<ValueParameterDescriptor, PossiblyCoercedValue>) =
actualCallee: DataFlowIR.FunctionSymbol.Declared,
parameters: List<PossiblyCoercedValue>) =
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<IrBranchImpl>()
@@ -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.
@@ -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 }
)
}