[K/N] Support ConstantValue in global analyses
This commit is contained in:
+1
-1
@@ -111,7 +111,7 @@ internal class CallGraphBuilder(
|
||||
is DataFlowIR.Node.Call -> block(node)
|
||||
|
||||
is DataFlowIR.Node.Singleton ->
|
||||
node.constructor?.let { block(DataFlowIR.Node.Call(it, emptyList(), node.type, null)) }
|
||||
node.constructor?.let { block(DataFlowIR.Node.Call(it, node.arguments ?: emptyList(), node.type, null)) }
|
||||
|
||||
is DataFlowIR.Node.ArrayRead ->
|
||||
block(DataFlowIR.Node.Call(
|
||||
|
||||
+61
-29
@@ -11,14 +11,9 @@ import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
|
||||
import org.jetbrains.kotlin.backend.common.peek
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.getInlinedClassNative
|
||||
import org.jetbrains.kotlin.backend.konan.ir.actualCallee
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isAny
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isObjCObjectType
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isVirtualCall
|
||||
import org.jetbrains.kotlin.backend.konan.logMultiple
|
||||
import org.jetbrains.kotlin.backend.konan.lower.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -127,17 +122,6 @@ private class ExpressionValuesExtractor(val context: Context,
|
||||
|
||||
is IrWhen -> expression.branches.forEach { forEachValue(it.result, block) }
|
||||
|
||||
is IrMemberAccessExpression<*> -> block(expression)
|
||||
|
||||
is IrGetValue -> block(expression)
|
||||
|
||||
is IrGetField -> block(expression)
|
||||
|
||||
is IrVararg -> /* Sometimes, we keep vararg till codegen phase (for constant arrays). */
|
||||
block(expression)
|
||||
|
||||
is IrConst<*> -> block(expression)
|
||||
|
||||
is IrTypeOperatorCall -> {
|
||||
if (!expression.operator.isCast())
|
||||
block(expression)
|
||||
@@ -155,11 +139,10 @@ private class ExpressionValuesExtractor(val context: Context,
|
||||
expression.catches.forEach { forEachValue(it.result, block) }
|
||||
}
|
||||
|
||||
is IrGetObjectValue -> block(expression)
|
||||
|
||||
is IrFunctionReference -> block(expression)
|
||||
|
||||
is IrSetField -> block(expression)
|
||||
is IrVararg, /* Sometimes, we keep vararg till codegen phase (for constant arrays). */
|
||||
is IrMemberAccessExpression<*>, is IrGetValue, is IrGetField, is IrConst<*>,
|
||||
is IrGetObjectValue, is IrFunctionReference, is IrSetField,
|
||||
is IrConstantValue -> block(expression)
|
||||
|
||||
else -> when {
|
||||
expression.type.isUnit() -> unit
|
||||
@@ -324,7 +307,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
is IrGetObjectValue,
|
||||
is IrVararg,
|
||||
is IrConst<*>,
|
||||
is IrTypeOperatorCall ->
|
||||
is IrTypeOperatorCall,
|
||||
is IrConstantPrimitive ->
|
||||
expressions += expression to currentLoop
|
||||
}
|
||||
|
||||
@@ -426,6 +410,36 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
super.visitVariable(declaration)
|
||||
declaration.initializer?.let { assignValue(declaration, it) }
|
||||
}
|
||||
|
||||
override fun visitConstantArray(expression: IrConstantArray) {
|
||||
super.visitConstantArray(expression)
|
||||
expressions += expression to currentLoop
|
||||
val arrayClass = expression.type.classOrNull
|
||||
val arraySetSymbol = context.ir.symbols.arraySet[arrayClass] ?: error("Unexpected array type ${expression.type.render()}")
|
||||
val isGeneric = arrayClass == context.irBuiltIns.arrayClass
|
||||
expression.elements.forEachIndexed { index, value ->
|
||||
val call = IrCallImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
context.irBuiltIns.unitType,
|
||||
arraySetSymbol,
|
||||
typeArgumentsCount = if (isGeneric) 1 else 0,
|
||||
valueArgumentsCount = 2
|
||||
).apply {
|
||||
dispatchReceiver = expression
|
||||
if (isGeneric) putTypeArgument(0, value.type)
|
||||
val constInt = IrConstImpl.int(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.irBuiltIns.intType, index)
|
||||
expressions += constInt to currentLoop
|
||||
putValueArgument(0, constInt)
|
||||
putValueArgument(1, value)
|
||||
}
|
||||
expressions += call to currentLoop
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstantObject(expression: IrConstantObject) {
|
||||
super.visitConstantObject(expression)
|
||||
expressions += expression to currentLoop
|
||||
}
|
||||
}
|
||||
|
||||
private val symbols = context.ir.symbols
|
||||
@@ -585,17 +599,20 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapReturnType(actualType: IrType, returnType: IrType): DataFlowIR.Type {
|
||||
val returnedInlinedClass = returnType.getInlinedClassNative()
|
||||
private fun mapWrappedType(actualType: IrType, wrapperType: IrType): DataFlowIR.Type {
|
||||
val wrapperInlinedClass = wrapperType.getInlinedClassNative()
|
||||
val actualInlinedClass = actualType.getInlinedClassNative()
|
||||
|
||||
return if (returnedInlinedClass == null) {
|
||||
return if (wrapperInlinedClass == null) {
|
||||
if (actualInlinedClass == null) symbolTable.mapType(actualType) else symbolTable.mapClassReferenceType(actualInlinedClass)
|
||||
} else {
|
||||
symbolTable.mapType(returnType)
|
||||
symbolTable.mapType(wrapperType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapReturnType(actualType: IrType, returnType: IrType) = mapWrappedType(actualType, returnType)
|
||||
|
||||
|
||||
private fun getNode(expression: IrExpression): Scoped<DataFlowIR.Node> {
|
||||
if (expression is IrGetValue) {
|
||||
val valueDeclaration = expression.symbol.owner
|
||||
@@ -664,6 +681,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
else
|
||||
DataFlowIR.Node.SimpleConst(symbolTable.mapType(value.type), value.value!!)
|
||||
|
||||
is IrConstantPrimitive ->
|
||||
if (value.value.value == null)
|
||||
DataFlowIR.Node.Null
|
||||
else
|
||||
DataFlowIR.Node.SimpleConst(mapWrappedType(value.value.type, value.type), value.value.value!!)
|
||||
|
||||
is IrGetObjectValue -> {
|
||||
val constructor = if (value.type.isNothing()) {
|
||||
// <Nothing> is not a singleton though its instance is get with <IrGetObject> operation.
|
||||
@@ -677,7 +700,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
symbolTable.mapFunction(objectClass.constructors.single())
|
||||
}
|
||||
}
|
||||
DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), constructor)
|
||||
DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), constructor, emptyList())
|
||||
}
|
||||
|
||||
is IrConstructorCall -> {
|
||||
@@ -847,6 +870,15 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
DataFlowIR.Node.Const(symbolTable.mapType(value.type)) // All operators except casts are basically constants.
|
||||
}
|
||||
|
||||
is IrConstantArray ->
|
||||
DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), null, null)
|
||||
is IrConstantObject ->
|
||||
DataFlowIR.Node.Singleton(
|
||||
symbolTable.mapType(value.type),
|
||||
symbolTable.mapFunction(value.constructor.owner),
|
||||
value.valueArguments.map { expressionToEdge(it) }
|
||||
)
|
||||
|
||||
else -> TODO("Unknown expression: ${ir2stringWhole(value)}")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -258,7 +258,7 @@ internal object DataFlowIR {
|
||||
arguments: List<Edge>, returnType: Type, irCallSite: IrCall?)
|
||||
: VirtualCall(callee, arguments, receiverType, returnType, irCallSite)
|
||||
|
||||
class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node()
|
||||
class Singleton(val type: Type, val constructor: FunctionSymbol?, val arguments: List<Edge>?) : Node()
|
||||
|
||||
class AllocInstance(val type: Type, val irCallSite: IrCall?) : Node()
|
||||
|
||||
|
||||
+10
-1
@@ -1194,7 +1194,16 @@ internal object DevirtualizationAnalysis {
|
||||
val type = node.type.resolved()
|
||||
addInstantiatingClass(type)
|
||||
val instanceNode = concreteClass(type)
|
||||
node.constructor?.let { doCall(it, listOf(instanceNode), type) }
|
||||
node.constructor?.let {
|
||||
doCall(
|
||||
it,
|
||||
@OptIn(ExperimentalStdlibApi::class) buildList {
|
||||
add(instanceNode)
|
||||
node.arguments?.forEach { add(edgeToConstraintNode(it)) }
|
||||
},
|
||||
type
|
||||
)
|
||||
}
|
||||
instanceNode
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user