Turned on bridges inlining
This commit is contained in:
+38
-17
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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())
|
||||
|
||||
+29
-5
@@ -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)
|
||||
|
||||
+31
-10
@@ -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
|
||||
|
||||
+23
-12
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+80
-99
@@ -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.
|
||||
|
||||
+3
-4
@@ -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 }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user