DFG: Moved parameter & return types from body to symbol
This commit is contained in:
-17
@@ -424,7 +424,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol
|
||||
|
||||
private val getContinuationSymbol = context.ir.symbols.getContinuation
|
||||
private val continuationType = getContinuationSymbol.descriptor.returnType!!
|
||||
|
||||
private val arrayGetSymbol = context.ir.symbols.arrayGet
|
||||
private val arraySetSymbol = context.ir.symbols.arraySet
|
||||
@@ -471,12 +470,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
)
|
||||
}
|
||||
|
||||
private fun choosePrimary(erasure: List<ClassDescriptor>): ClassDescriptor {
|
||||
if (erasure.size == 1) return erasure[0]
|
||||
// A parameter with constraints - choose class if exists.
|
||||
return erasure.singleOrNull { !it.isInterface } ?: context.ir.symbols.any.owner
|
||||
}
|
||||
|
||||
fun build(): DataFlowIR.Function {
|
||||
val isSuspend = descriptor is IrSimpleFunction && descriptor.isSuspend
|
||||
|
||||
@@ -506,14 +499,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
val allNodes = nodes.values + variables.values + templateParameters.values + returnsNode + throwsNode +
|
||||
(if (isSuspend) listOf(continuationParameter!!) else emptyList())
|
||||
|
||||
val parameterTypes = (allParameters.map { it.type } + (if (isSuspend) listOf(continuationType) else emptyList()))
|
||||
.map { symbolTable.mapClass(choosePrimary(it.erasure(context))) }
|
||||
.toTypedArray()
|
||||
val returnType = if (isSuspend) context.builtIns.anyType else returnNodeType
|
||||
return DataFlowIR.Function(
|
||||
symbol = symbolTable.mapFunction(descriptor),
|
||||
parameterTypes = parameterTypes,
|
||||
returnType = symbolTable.mapType(returnType),
|
||||
body = DataFlowIR.FunctionBody(allNodes.distinct().toList(), returnsNode, throwsNode)
|
||||
)
|
||||
}
|
||||
@@ -606,7 +593,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
symbolTable.mapClass(owner),
|
||||
callee.functionName.localHash.value,
|
||||
arguments,
|
||||
symbolTable.mapType(callee.returnType),
|
||||
value
|
||||
)
|
||||
} else {
|
||||
@@ -617,7 +603,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
symbolTable.mapClass(owner),
|
||||
vtableIndex,
|
||||
arguments,
|
||||
symbolTable.mapType(callee.returnType),
|
||||
value
|
||||
)
|
||||
}
|
||||
@@ -626,7 +611,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
DataFlowIR.Node.StaticCall(
|
||||
symbolTable.mapFunction(actualCallee),
|
||||
arguments,
|
||||
symbolTable.mapType(actualCallee.returnType),
|
||||
actualCallee.dispatchReceiverParameter?.let { symbolTable.mapType(it.type) },
|
||||
value
|
||||
)
|
||||
@@ -642,7 +626,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
DataFlowIR.Node.StaticCall(
|
||||
symbolTable.mapFunction(value.symbol.owner),
|
||||
arguments.map { expressionToEdge(it) },
|
||||
symbolTable.mapClass(context.ir.symbols.unit.owner),
|
||||
symbolTable.mapType(thiz.type),
|
||||
value
|
||||
)
|
||||
|
||||
+81
-77
@@ -300,56 +300,59 @@ internal object DFGSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalFunctionSymbol(val hash: Long, val numberOfParameters: Int, val isGlobalInitializer: Boolean,
|
||||
val escapes: Int?, val pointsTo: IntArray?, val name: String?) {
|
||||
class FunctionSymbolBase(val parameterTypes: IntArray, val returnType: Int, val isGlobalInitializer: Boolean) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readBoolean(), data.readNullableInt(),
|
||||
constructor(data: ArraySlice) : this(data.readIntArray(), data.readInt(), data.readBoolean())
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeIntArray(parameterTypes)
|
||||
result.writeInt(returnType)
|
||||
result.writeBoolean(isGlobalInitializer)
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalFunctionSymbol(val hash: Long, val escapes: Int?, val pointsTo: IntArray?, val name: String?) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readLong(), data.readNullableInt(),
|
||||
data.readNullable { readIntArray() }, data.readNullableString())
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeLong(hash)
|
||||
result.writeInt(numberOfParameters)
|
||||
result.writeBoolean(isGlobalInitializer)
|
||||
result.writeNullableInt(escapes)
|
||||
result.writeNullable(pointsTo) { writeIntArray(it) }
|
||||
result.writeNullableString(name)
|
||||
}
|
||||
}
|
||||
|
||||
class PublicFunctionSymbol(val hash: Long, val numberOfParameters: Int, val isGlobalInitializer: Boolean,
|
||||
val index: Int, val bridgeTarget: Int?, val name: String?) {
|
||||
class PublicFunctionSymbol(val hash: Long, val index: Int, val bridgeTarget: Int?, val name: String?) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readBoolean(), data.readInt(),
|
||||
constructor(data: ArraySlice) : this(data.readLong(), data.readInt(),
|
||||
data.readNullableInt(), data.readNullableString())
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeLong(hash)
|
||||
result.writeInt(numberOfParameters)
|
||||
result.writeBoolean(isGlobalInitializer)
|
||||
result.writeInt(index)
|
||||
result.writeNullableInt(bridgeTarget)
|
||||
result.writeNullableString(name)
|
||||
}
|
||||
}
|
||||
|
||||
class PrivateFunctionSymbol(val index: Int, val numberOfParameters: Int, val isGlobalInitializer: Boolean,
|
||||
val bridgeTarget: Int?, val name: String?) {
|
||||
class PrivateFunctionSymbol(val index: Int, val bridgeTarget: Int?, val name: String?) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readInt(), data.readInt(), data.readBoolean(),
|
||||
data.readNullableInt(), data.readNullableString())
|
||||
constructor(data: ArraySlice) : this(data.readInt(), data.readNullableInt(), data.readNullableString())
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeInt(index)
|
||||
result.writeInt(numberOfParameters)
|
||||
result.writeBoolean(isGlobalInitializer)
|
||||
result.writeNullableInt(bridgeTarget)
|
||||
result.writeNullableString(name)
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionSymbol(val external: ExternalFunctionSymbol?, val public: PublicFunctionSymbol?, val private: PrivateFunctionSymbol?) {
|
||||
class FunctionSymbol(val base: FunctionSymbolBase, val external: ExternalFunctionSymbol?,
|
||||
val public: PublicFunctionSymbol?, val private: PrivateFunctionSymbol?) {
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
base.write(result)
|
||||
result.writeByte(
|
||||
when {
|
||||
external != null -> 1
|
||||
@@ -364,22 +367,23 @@ internal object DFGSerializer {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun external(hash: Long, numberOfParameters: Int, isGlobalInitializer: Boolean, escapes: Int?, pointsTo: IntArray?, name: String?) =
|
||||
FunctionSymbol(ExternalFunctionSymbol(hash, numberOfParameters, isGlobalInitializer, escapes, pointsTo, name), null, null)
|
||||
fun external(base: FunctionSymbolBase, hash: Long, escapes: Int?, pointsTo: IntArray?, name: String?) =
|
||||
FunctionSymbol(base, ExternalFunctionSymbol(hash, escapes, pointsTo, name), null, null)
|
||||
|
||||
fun public(hash: Long, numberOfParameters: Int, isGlobalInitializer: Boolean, index: Int, bridgeTarget: Int?, name: String?) =
|
||||
FunctionSymbol(null, PublicFunctionSymbol(hash, numberOfParameters, isGlobalInitializer, index, bridgeTarget, name), null)
|
||||
fun public(base: FunctionSymbolBase, hash: Long, index: Int, bridgeTarget: Int?, name: String?) =
|
||||
FunctionSymbol(base, null, PublicFunctionSymbol(hash, index, bridgeTarget, name), null)
|
||||
|
||||
fun private(index: Int, numberOfParameters: Int, isGlobalInitializer: Boolean, bridgeTarget: Int?, name: String?) =
|
||||
FunctionSymbol(null, null, PrivateFunctionSymbol(index, numberOfParameters, isGlobalInitializer, bridgeTarget, name))
|
||||
fun private(base: FunctionSymbolBase, index: Int, bridgeTarget: Int?, name: String?) =
|
||||
FunctionSymbol(base, null, null, PrivateFunctionSymbol(index, bridgeTarget, name))
|
||||
|
||||
fun read(data: ArraySlice): FunctionSymbol {
|
||||
val base = FunctionSymbolBase(data)
|
||||
val tag = data.readByte().toInt()
|
||||
return when (tag) {
|
||||
1 -> FunctionSymbol(ExternalFunctionSymbol(data), null, null)
|
||||
2 -> FunctionSymbol(null, PublicFunctionSymbol(data), null)
|
||||
3 -> FunctionSymbol(null, null, PrivateFunctionSymbol(data))
|
||||
else -> FunctionSymbol(null, null, null)
|
||||
1 -> FunctionSymbol(base, ExternalFunctionSymbol(data), null, null)
|
||||
2 -> FunctionSymbol(base, null, PublicFunctionSymbol(data), null)
|
||||
3 -> FunctionSymbol(base, null, null, PrivateFunctionSymbol(data))
|
||||
else -> FunctionSymbol(base, null, null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,14 +438,13 @@ internal object DFGSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
class Call(val callee: Int, val arguments: Array<Edge>, val returnType: Int) {
|
||||
class Call(val callee: Int, val arguments: Array<Edge>) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readInt(), data.readArray { Edge(this) }, data.readInt())
|
||||
constructor(data: ArraySlice) : this(data.readInt(), data.readArray { Edge(this) })
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeInt(callee)
|
||||
result.writeArray(arguments) { it.write(this) }
|
||||
result.writeInt(returnType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,12 +458,13 @@ internal object DFGSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
class NewObject(val call: Call) {
|
||||
class NewObject(val call: Call, val constructedType: Int) {
|
||||
|
||||
constructor(data: ArraySlice) : this(Call(data))
|
||||
constructor(data: ArraySlice) : this(Call(data), data.readInt())
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
call.write(result)
|
||||
result.writeInt(constructedType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,8 +633,8 @@ internal object DFGSerializer {
|
||||
fun staticCall(call: Call, receiverType: Int?) =
|
||||
Node().also { it.staticCall = StaticCall(call, receiverType) }
|
||||
|
||||
fun newObject(call: Call) =
|
||||
Node().also { it.newObject = NewObject(call) }
|
||||
fun newObject(call: Call, constructedType: Int) =
|
||||
Node().also { it.newObject = NewObject(call, constructedType) }
|
||||
|
||||
fun vtableCall(virtualCall: VirtualCall, calleeVtableIndex: Int) =
|
||||
Node().also { it.vtableCall = VtableCall(virtualCall, calleeVtableIndex) }
|
||||
@@ -690,14 +694,12 @@ internal object DFGSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
class Function(val symbol: Int, val parameterTypes: IntArray, val returnType: Int, val body: FunctionBody) {
|
||||
class Function(val symbol: Int, val body: FunctionBody) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readInt(), data.readIntArray(), data.readInt(), FunctionBody(data))
|
||||
constructor(data: ArraySlice) : this(data.readInt(), FunctionBody(data))
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeInt(symbol)
|
||||
result.writeIntArray(parameterTypes)
|
||||
result.writeInt(returnType)
|
||||
body.write(result)
|
||||
}
|
||||
}
|
||||
@@ -790,25 +792,30 @@ internal object DFGSerializer {
|
||||
val functionSymbols = functionSymbolMap.entries
|
||||
.sortedBy { it.value }
|
||||
.map {
|
||||
val functionSymbol = it.key
|
||||
val numberOfParameters = functionSymbol.numberOfParameters
|
||||
val isGlobalInitializer = functionSymbol.isGlobalInitializer
|
||||
val name = functionSymbol.name
|
||||
val bridgeTarget = (functionSymbol as? DataFlowIR.FunctionSymbol.Declared)?.let { functionSymbolMap[it] }
|
||||
when (functionSymbol) {
|
||||
|
||||
fun buildFunctionSymbolBase(symbol: DataFlowIR.FunctionSymbol) =
|
||||
FunctionSymbolBase(
|
||||
symbol.parameterTypes.map { typeMap[it]!! }.toIntArray(),
|
||||
typeMap[symbol.returnType]!!,
|
||||
symbol.isGlobalInitializer
|
||||
)
|
||||
|
||||
val symbol = it.key
|
||||
val bridgeTarget = (symbol as? DataFlowIR.FunctionSymbol.Declared)?.let { functionSymbolMap[it] }
|
||||
when (symbol) {
|
||||
is DataFlowIR.FunctionSymbol.External ->
|
||||
FunctionSymbol.external(functionSymbol.hash, numberOfParameters, isGlobalInitializer,
|
||||
functionSymbol.escapes, functionSymbol.pointsTo, name)
|
||||
FunctionSymbol.external(buildFunctionSymbolBase(symbol), symbol.hash,
|
||||
symbol.escapes, symbol.pointsTo, symbol.name)
|
||||
|
||||
is DataFlowIR.FunctionSymbol.Public ->
|
||||
FunctionSymbol.public(functionSymbol.hash, numberOfParameters,
|
||||
isGlobalInitializer, functionSymbol.symbolTableIndex, bridgeTarget, name)
|
||||
FunctionSymbol.public(buildFunctionSymbolBase(symbol), symbol.hash,
|
||||
symbol.symbolTableIndex, bridgeTarget, symbol.name)
|
||||
|
||||
is DataFlowIR.FunctionSymbol.Private ->
|
||||
FunctionSymbol.private(functionSymbol.symbolTableIndex, numberOfParameters,
|
||||
isGlobalInitializer, bridgeTarget, name)
|
||||
FunctionSymbol.private(buildFunctionSymbolBase(symbol), symbol.symbolTableIndex,
|
||||
bridgeTarget, symbol.name)
|
||||
|
||||
else -> error("Unknown function symbol $functionSymbol")
|
||||
else -> error("Unknown function symbol $symbol")
|
||||
}
|
||||
}
|
||||
.toTypedArray()
|
||||
@@ -827,8 +834,7 @@ internal object DFGSerializer {
|
||||
fun buildCall(call: DataFlowIR.Node.Call) =
|
||||
Call(
|
||||
functionSymbolMap[call.callee]!!,
|
||||
call.arguments.map { buildEdge(it) }.toTypedArray(),
|
||||
typeMap[call.returnType]!!
|
||||
call.arguments.map { buildEdge(it) }.toTypedArray()
|
||||
)
|
||||
|
||||
fun buildVirtualCall(virtualCall: DataFlowIR.Node.VirtualCall) =
|
||||
@@ -845,7 +851,8 @@ internal object DFGSerializer {
|
||||
is DataFlowIR.Node.StaticCall ->
|
||||
Node.staticCall(buildCall(node), node.receiverType?.let { typeMap[it]!! })
|
||||
|
||||
is DataFlowIR.Node.NewObject -> Node.newObject(buildCall(node))
|
||||
is DataFlowIR.Node.NewObject ->
|
||||
Node.newObject(buildCall(node), typeMap[node.constructedType]!!)
|
||||
|
||||
is DataFlowIR.Node.VtableCall ->
|
||||
Node.vtableCall(buildVirtualCall(node), node.calleeVtableIndex)
|
||||
@@ -876,10 +883,8 @@ internal object DFGSerializer {
|
||||
}
|
||||
.toTypedArray()
|
||||
Function(
|
||||
functionSymbolMap[function.symbol]!!,
|
||||
function.parameterTypes.map { typeMap[it]!! }.toIntArray(),
|
||||
typeMap[function.returnType]!!,
|
||||
FunctionBody(nodes, nodeMap[body.returns]!!, nodeMap[body.throws]!!)
|
||||
symbol = functionSymbolMap[function.symbol]!!,
|
||||
body = FunctionBody(nodes, nodeMap[body.returns]!!, nodeMap[body.throws]!!)
|
||||
)
|
||||
}
|
||||
.toTypedArray()
|
||||
@@ -953,20 +958,21 @@ internal object DFGSerializer {
|
||||
}
|
||||
|
||||
val functionSymbols = symbolTable.functionSymbols.map {
|
||||
val isGlobalInitializer = it.base.isGlobalInitializer
|
||||
val external = it.external
|
||||
val public = it.public
|
||||
val private = it.private
|
||||
when {
|
||||
external != null ->
|
||||
DataFlowIR.FunctionSymbol.External(external.hash, external.numberOfParameters,
|
||||
external.isGlobalInitializer, external.escapes, external.pointsTo, external.name)
|
||||
DataFlowIR.FunctionSymbol.External(external.hash,
|
||||
isGlobalInitializer, external.escapes, external.pointsTo, external.name)
|
||||
|
||||
public != null -> {
|
||||
val symbolTableIndex = public.index
|
||||
if (symbolTableIndex >= 0)
|
||||
++module.numberOfFunctions
|
||||
DataFlowIR.FunctionSymbol.Public(public.hash, public.numberOfParameters, module,
|
||||
symbolTableIndex, public.isGlobalInitializer, null, public.name).also {
|
||||
DataFlowIR.FunctionSymbol.Public(public.hash,
|
||||
module, symbolTableIndex, isGlobalInitializer, null, public.name).also {
|
||||
publicFunctionsMap.put(it.hash, it)
|
||||
}
|
||||
}
|
||||
@@ -975,9 +981,12 @@ internal object DFGSerializer {
|
||||
val symbolTableIndex = private!!.index
|
||||
if (symbolTableIndex >= 0)
|
||||
++module.numberOfFunctions
|
||||
DataFlowIR.FunctionSymbol.Private(privateFunIndex++, private.numberOfParameters, module,
|
||||
symbolTableIndex, private.isGlobalInitializer, null, private.name)
|
||||
DataFlowIR.FunctionSymbol.Private(privateFunIndex++,
|
||||
module, symbolTableIndex, isGlobalInitializer, null, private.name)
|
||||
}
|
||||
}.apply {
|
||||
parameterTypes = it.base.parameterTypes.map { types[it] }.toTypedArray()
|
||||
returnType = types[it.base.returnType]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,8 +1027,7 @@ internal object DFGSerializer {
|
||||
DataFlowIR.Node.Call(
|
||||
functionSymbols[call.callee],
|
||||
call.arguments.map { deserializeEdge(it) },
|
||||
types[call.returnType],
|
||||
null
|
||||
irCallSite = null
|
||||
)
|
||||
|
||||
fun deserializeVirtualCall(virtualCall: VirtualCall): DataFlowIR.Node.VirtualCall {
|
||||
@@ -1027,9 +1035,8 @@ internal object DFGSerializer {
|
||||
return DataFlowIR.Node.VirtualCall(
|
||||
call.callee,
|
||||
call.arguments,
|
||||
call.returnType,
|
||||
types[virtualCall.receiverType],
|
||||
null
|
||||
irCallSite = null
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1049,12 +1056,13 @@ internal object DFGSerializer {
|
||||
val staticCall = it.staticCall!!
|
||||
val call = deserializeCall(staticCall.call)
|
||||
val receiverType = staticCall.receiverType?.let { types[it] }
|
||||
DataFlowIR.Node.StaticCall(call.callee, call.arguments, call.returnType, receiverType, null)
|
||||
DataFlowIR.Node.StaticCall(call.callee, call.arguments, receiverType, irCallSite = null)
|
||||
}
|
||||
|
||||
NodeType.NEW_OBJECT -> {
|
||||
val call = deserializeCall(it.newObject!!.call)
|
||||
DataFlowIR.Node.NewObject(call.callee, call.arguments, call.returnType, null)
|
||||
val newObject = it.newObject!!
|
||||
val call = deserializeCall(newObject.call)
|
||||
DataFlowIR.Node.NewObject(call.callee, call.arguments, types[newObject.constructedType], irCallSite = null)
|
||||
}
|
||||
|
||||
NodeType.VTABLE_CALL -> {
|
||||
@@ -1065,8 +1073,7 @@ internal object DFGSerializer {
|
||||
virtualCall.receiverType,
|
||||
vtableCall.calleeVtableIndex,
|
||||
virtualCall.arguments,
|
||||
virtualCall.returnType,
|
||||
virtualCall.callSite
|
||||
virtualCall.irCallSite
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1078,8 +1085,7 @@ internal object DFGSerializer {
|
||||
virtualCall.receiverType,
|
||||
itableCall.calleeHash,
|
||||
virtualCall.arguments,
|
||||
virtualCall.returnType,
|
||||
virtualCall.callSite
|
||||
virtualCall.irCallSite
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1185,8 +1191,6 @@ internal object DFGSerializer {
|
||||
val symbol = functionSymbols[it.symbol]
|
||||
val function = DataFlowIR.Function(
|
||||
symbol = symbol,
|
||||
parameterTypes = it.parameterTypes.map { types[it] }.toTypedArray(),
|
||||
returnType = types[it.returnType],
|
||||
body = deserializeBody(it.body)
|
||||
)
|
||||
functions.put(symbol, function)
|
||||
|
||||
+102
-73
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.konan.optimizations
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.target
|
||||
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.functionName
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.isExported
|
||||
@@ -117,10 +118,13 @@ internal object DataFlowIR {
|
||||
var numberOfClasses = 0
|
||||
}
|
||||
|
||||
abstract class FunctionSymbol(val numberOfParameters: Int, val isGlobalInitializer: Boolean, val name: String?) {
|
||||
class External(val hash: Long, numberOfParameters: Int, isGlobalInitializer: Boolean,
|
||||
abstract class FunctionSymbol(val isGlobalInitializer: Boolean, val name: String?) {
|
||||
lateinit var parameterTypes: Array<Type>
|
||||
lateinit var returnType: Type
|
||||
|
||||
class External(val hash: Long, isGlobalInitializer: Boolean,
|
||||
val escapes: Int?, val pointsTo: IntArray?, name: String? = null)
|
||||
: FunctionSymbol(numberOfParameters, isGlobalInitializer, name) {
|
||||
: FunctionSymbol(isGlobalInitializer, name) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@@ -138,15 +142,16 @@ internal object DataFlowIR {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Declared(numberOfParameters: Int, val module: Module, val symbolTableIndex: Int,
|
||||
abstract class Declared(val module: Module, val symbolTableIndex: Int,
|
||||
isGlobalInitializer: Boolean, var bridgeTarget: FunctionSymbol?, name: String?)
|
||||
: FunctionSymbol(numberOfParameters, isGlobalInitializer, name) {
|
||||
: FunctionSymbol(isGlobalInitializer, name) {
|
||||
|
||||
}
|
||||
|
||||
class Public(val hash: Long, numberOfParameters: Int, module: Module, symbolTableIndex: Int,
|
||||
class Public(val hash: Long, module: Module, symbolTableIndex: Int,
|
||||
isGlobalInitializer: Boolean, bridgeTarget: FunctionSymbol?, name: String? = null)
|
||||
: Declared(numberOfParameters, module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) {
|
||||
: Declared(module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Public) return false
|
||||
@@ -163,9 +168,10 @@ internal object DataFlowIR {
|
||||
}
|
||||
}
|
||||
|
||||
class Private(val index: Int, numberOfParameters: Int, module: Module, symbolTableIndex: Int,
|
||||
class Private(val index: Int, module: Module, symbolTableIndex: Int,
|
||||
isGlobalInitializer: Boolean, bridgeTarget: FunctionSymbol?, name: String? = null)
|
||||
: Declared(numberOfParameters, module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) {
|
||||
: Declared(module, symbolTableIndex, isGlobalInitializer, bridgeTarget, name) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Private) return false
|
||||
@@ -205,27 +211,27 @@ internal object DataFlowIR {
|
||||
|
||||
class Const(val type: Type) : Node()
|
||||
|
||||
open class Call(val callee: FunctionSymbol, val arguments: List<Edge>, val returnType: Type,
|
||||
open val callSite: IrFunctionAccessExpression?) : Node()
|
||||
open class Call(val callee: FunctionSymbol, val arguments: List<Edge>,
|
||||
open val irCallSite: IrFunctionAccessExpression?) : Node()
|
||||
|
||||
class StaticCall(callee: FunctionSymbol, arguments: List<Edge>, returnType: Type,
|
||||
val receiverType: Type?, callSite: IrFunctionAccessExpression?)
|
||||
: Call(callee, arguments, returnType, callSite)
|
||||
class StaticCall(callee: FunctionSymbol, arguments: List<Edge>,
|
||||
val receiverType: Type?, irCallSite: IrFunctionAccessExpression?)
|
||||
: Call(callee, arguments, irCallSite)
|
||||
|
||||
class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, type: Type, override val callSite: IrCall?)
|
||||
: Call(constructor, arguments, type, callSite)
|
||||
class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type, override val irCallSite: IrCall?)
|
||||
: Call(constructor, arguments, irCallSite)
|
||||
|
||||
open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>, returnType: Type,
|
||||
val receiverType: Type, override val callSite: IrCall?)
|
||||
: Call(callee, arguments, returnType, callSite)
|
||||
open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>,
|
||||
val receiverType: Type, override val irCallSite: IrCall?)
|
||||
: Call(callee, arguments, irCallSite)
|
||||
|
||||
class VtableCall(callee: FunctionSymbol, receiverType: Type, val calleeVtableIndex: Int,
|
||||
arguments: List<Edge>, returnType: Type, callSite: IrCall?)
|
||||
: VirtualCall(callee, arguments, returnType, receiverType, callSite)
|
||||
arguments: List<Edge>, irCallSite: IrCall?)
|
||||
: VirtualCall(callee, arguments, receiverType, irCallSite)
|
||||
|
||||
class ItableCall(callee: FunctionSymbol, receiverType: Type, val calleeHash: Long,
|
||||
arguments: List<Edge>, returnType: Type, callSite: IrCall?)
|
||||
: VirtualCall(callee, arguments, returnType, receiverType, callSite)
|
||||
arguments: List<Edge>, irCallSite: IrCall?)
|
||||
: VirtualCall(callee, arguments, receiverType, irCallSite)
|
||||
|
||||
class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node()
|
||||
|
||||
@@ -233,7 +239,7 @@ internal object DataFlowIR {
|
||||
|
||||
class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node()
|
||||
|
||||
class ArrayRead(val array: Edge, val index: Edge, val callSite: IrCall?) : Node()
|
||||
class ArrayRead(val array: Edge, val index: Edge, val irCallSite: IrCall?) : Node()
|
||||
|
||||
class ArrayWrite(val array: Edge, val index: Edge, val value: Edge) : Node()
|
||||
|
||||
@@ -244,14 +250,11 @@ internal object DataFlowIR {
|
||||
|
||||
class FunctionBody(val nodes: List<Node>, val returns: Node.Variable, val throws: Node.Variable)
|
||||
|
||||
class Function(val symbol: FunctionSymbol,
|
||||
val parameterTypes: Array<Type>,
|
||||
val returnType: Type,
|
||||
val body: FunctionBody) {
|
||||
class Function(val symbol: FunctionSymbol, val body: FunctionBody) {
|
||||
|
||||
fun debugOutput() {
|
||||
println("FUNCTION $symbol")
|
||||
println("Params: ${parameterTypes.contentToString()}")
|
||||
println("Params: ${symbol.parameterTypes.contentToString()}")
|
||||
val ids = body.nodes.withIndex().associateBy({ it.value }, { it.index })
|
||||
body.nodes.forEach {
|
||||
println(" NODE #${ids[it]!!}")
|
||||
@@ -320,7 +323,7 @@ internal object DataFlowIR {
|
||||
is Node.NewObject -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" NEW OBJECT ${node.callee}")
|
||||
result.appendln(" TYPE ${node.returnType}")
|
||||
result.appendln(" CONSTRUCTED TYPE ${node.constructedType}")
|
||||
node.arguments.forEach {
|
||||
result.append(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
@@ -439,6 +442,9 @@ internal object DataFlowIR {
|
||||
NAME_POINTS_TO, NoLookupLocation.FROM_BACKEND) as org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
|
||||
|
||||
private val getContinuationSymbol = context.ir.symbols.getContinuation
|
||||
private val continuationType = getContinuationSymbol.descriptor.returnType!!
|
||||
|
||||
var privateTypeIndex = 0
|
||||
var privateFunIndex = 0
|
||||
|
||||
@@ -486,6 +492,10 @@ internal object DataFlowIR {
|
||||
Type.Public(name.localHash.value, isFinal, isAbstract, correspondingValueType, module, symbolTableIndex, takeName { name })
|
||||
else
|
||||
Type.Private(privateTypeIndex++, isFinal, isAbstract, correspondingValueType, module, symbolTableIndex, takeName { name })
|
||||
|
||||
classMap[descriptor] = type
|
||||
|
||||
type.superTypes += descriptor.defaultType.immediateSupertypes().map { mapType(it) }
|
||||
if (!isAbstract) {
|
||||
val vtableBuilder = context.getVtableBuilder(descriptor)
|
||||
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) }
|
||||
@@ -493,8 +503,6 @@ internal object DataFlowIR {
|
||||
type.itable[it.overriddenDescriptor.functionName.localHash.value] = mapFunction(it.getImplementation(context)!!)
|
||||
}
|
||||
}
|
||||
classMap.put(descriptor, type)
|
||||
type.superTypes += descriptor.defaultType.immediateSupertypes().map { mapType(it) }
|
||||
return type
|
||||
}
|
||||
|
||||
@@ -512,50 +520,71 @@ internal object DataFlowIR {
|
||||
|
||||
private val FunctionDescriptor.internalName get() = getFqName(this).asString() + "#internal"
|
||||
|
||||
fun mapFunction(descriptor: DeclarationDescriptor): FunctionSymbol = descriptor.original.let {
|
||||
functionMap.getOrPut(it) {
|
||||
when (it) {
|
||||
is IrField -> {
|
||||
// A global property initializer.
|
||||
assert (it.parent !is IrClass) { "All local properties initializers should've been lowered" }
|
||||
FunctionSymbol.Private(privateFunIndex++, 0, module, -1, true, null, takeName { "${it.symbolName}_init" })
|
||||
fun mapFunction(descriptor: DeclarationDescriptor): FunctionSymbol = when (descriptor) {
|
||||
is FunctionDescriptor -> mapFunction(descriptor)
|
||||
is IrField -> mapPropertyInitializer(descriptor)
|
||||
else -> error("Unknown descriptor: $descriptor")
|
||||
}
|
||||
|
||||
private fun mapFunction(descriptor: FunctionDescriptor): FunctionSymbol = descriptor.target.let {
|
||||
functionMap[it]?.let { return it }
|
||||
|
||||
val name = if (it.isExported()) it.symbolName else it.internalName
|
||||
val symbol = when {
|
||||
it.module != irModule.descriptor || it.isExternal || (it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB) -> {
|
||||
val escapesAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_ESCAPES)
|
||||
val pointsToAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_POINTS_TO)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val escapesBitMask = (escapesAnnotation?.allValueArguments?.get(escapesWhoDescriptor.name) as? ConstantValue<Int>)?.value
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val pointsToBitMask = (pointsToAnnotation?.allValueArguments?.get(pointsToOnWhomDescriptor.name) as? ConstantValue<List<IntValue>>)?.value
|
||||
FunctionSymbol.External(name.localHash.value, false, escapesBitMask,
|
||||
pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name })
|
||||
}
|
||||
|
||||
else -> {
|
||||
val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT
|
||||
val classDescriptor = it.containingDeclaration as? ClassDescriptor
|
||||
val bridgeTarget = it.bridgeTarget
|
||||
val isSpecialBridge = bridgeTarget.let {
|
||||
it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null
|
||||
}
|
||||
|
||||
is FunctionDescriptor -> {
|
||||
val name = if (it.isExported()) it.symbolName else it.internalName
|
||||
val numberOfParameters = it.allParameters.size + if (it.isSuspend) 1 else 0
|
||||
if (it.module != irModule.descriptor || it.isExternal || (it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB)) {
|
||||
val escapesAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_ESCAPES)
|
||||
val pointsToAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_POINTS_TO)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val escapesBitMask = (escapesAnnotation?.allValueArguments?.get(escapesWhoDescriptor.name) as? ConstantValue<Int>)?.value
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val pointsToBitMask = (pointsToAnnotation?.allValueArguments?.get(pointsToOnWhomDescriptor.name) as? ConstantValue<List<IntValue>>)?.value
|
||||
FunctionSymbol.External(name.localHash.value, numberOfParameters, false, escapesBitMask,
|
||||
pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name })
|
||||
} else {
|
||||
val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT
|
||||
val classDescriptor = it.containingDeclaration as? ClassDescriptor
|
||||
val bridgeTarget = it.bridgeTarget
|
||||
val isSpecialBridge = bridgeTarget.let {
|
||||
it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null
|
||||
}
|
||||
val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget)
|
||||
|
||||
val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null
|
||||
&& classDescriptor.kind != ClassKind.ANNOTATION_CLASS
|
||||
&& (it.isOverridableOrOverrides || bridgeTarget != null || !classDescriptor.isFinal())
|
||||
val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1
|
||||
if (it.isExported())
|
||||
FunctionSymbol.Public(name.localHash.value, numberOfParameters, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name })
|
||||
else
|
||||
FunctionSymbol.Private(privateFunIndex++, numberOfParameters, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name })
|
||||
}
|
||||
}
|
||||
|
||||
else -> error("Unknown descriptor: $it")
|
||||
val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget)
|
||||
val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null
|
||||
&& classDescriptor.kind != ClassKind.ANNOTATION_CLASS
|
||||
&& (it.isOverridableOrOverrides || bridgeTarget != null || !classDescriptor.isFinal())
|
||||
val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1
|
||||
if (it.isExported())
|
||||
FunctionSymbol.Public(name.localHash.value, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name })
|
||||
else
|
||||
FunctionSymbol.Private(privateFunIndex++, module, symbolTableIndex, false, bridgeTargetSymbol, takeName { name })
|
||||
}
|
||||
}
|
||||
functionMap[it] = symbol
|
||||
|
||||
symbol.parameterTypes =
|
||||
(descriptor.allParameters.map { it.type } + (if (descriptor.isSuspend) listOf(continuationType) else emptyList()))
|
||||
.map { mapClass(choosePrimary(it.erasure(context))) }
|
||||
.toTypedArray()
|
||||
symbol.returnType = mapType(if (descriptor.isSuspend)
|
||||
context.builtIns.anyType
|
||||
else
|
||||
descriptor.returnType)
|
||||
|
||||
return symbol
|
||||
}
|
||||
|
||||
private fun mapPropertyInitializer(descriptor: IrField): FunctionSymbol = descriptor.original.let {
|
||||
functionMap[it]?.let { return it }
|
||||
|
||||
assert(it.parent !is IrClass) { "All local properties initializers should've been lowered" }
|
||||
val symbol = FunctionSymbol.Private(privateFunIndex++, module, -1, true, null, takeName { "${it.symbolName}_init" })
|
||||
|
||||
functionMap[it] = symbol
|
||||
|
||||
symbol.parameterTypes = emptyArray()
|
||||
symbol.returnType = mapClass(context.ir.symbols.unit.owner)
|
||||
return symbol
|
||||
}
|
||||
|
||||
fun getPrivateFunctionsTableForExport() =
|
||||
|
||||
+33
-36
@@ -226,8 +226,7 @@ internal object Devirtualization {
|
||||
}
|
||||
}
|
||||
|
||||
private inner class InstantiationsSearcher(val functions: Map<DataFlowIR.FunctionSymbol, DataFlowIR.Function>,
|
||||
val rootSet: List<DataFlowIR.FunctionSymbol>,
|
||||
private inner class InstantiationsSearcher(val rootSet: List<DataFlowIR.FunctionSymbol>,
|
||||
val typeHierarchy: TypeHierarchy) {
|
||||
private val visited = mutableSetOf<DataFlowIR.FunctionSymbol>()
|
||||
private val typesVirtualCallSites = mutableMapOf<DataFlowIR.Type.Declared, MutableList<DataFlowIR.Node.VirtualCall>>()
|
||||
@@ -236,13 +235,12 @@ internal object Devirtualization {
|
||||
fun search(): Set<DataFlowIR.Type.Declared> {
|
||||
// Rapid Type Analysis: find all instantiations and conservatively estimate call graph.
|
||||
// Add all final parameters of the roots.
|
||||
rootSet.map { functions[it]!! }
|
||||
.forEach {
|
||||
it.parameterTypes
|
||||
.map { it.resolved() }
|
||||
.filter { it.isFinal }
|
||||
.forEach { addInstantiatingClass(it) }
|
||||
}
|
||||
rootSet.forEach {
|
||||
it.parameterTypes
|
||||
.map { it.resolved() }
|
||||
.filter { it.isFinal }
|
||||
.forEach { addInstantiatingClass(it) }
|
||||
}
|
||||
if (entryPoint == null) {
|
||||
// For library assume all public non-abstract classes could be instantiated.
|
||||
moduleDFG.symbolTable.classMap.values
|
||||
@@ -252,7 +250,7 @@ internal object Devirtualization {
|
||||
.forEach { addInstantiatingClass(it) }
|
||||
}
|
||||
// Traverse call graph from the roots.
|
||||
rootSet.forEach { dfs(it, functions[it]!!.returnType) }
|
||||
rootSet.forEach { dfs(it) }
|
||||
return instantiatingClasses
|
||||
}
|
||||
|
||||
@@ -281,7 +279,7 @@ internal object Devirtualization {
|
||||
|
||||
else -> error("Unreachable")
|
||||
}
|
||||
dfs(callee, virtualCall.returnType)
|
||||
dfs(callee)
|
||||
}
|
||||
|
||||
private fun checkSupertypes(type: DataFlowIR.Type.Declared,
|
||||
@@ -316,13 +314,13 @@ internal object Devirtualization {
|
||||
.forEach { checkSupertypes(it, inheritor, seenTypes) }
|
||||
}
|
||||
|
||||
private fun dfs(symbol: DataFlowIR.FunctionSymbol, returnType: DataFlowIR.Type) {
|
||||
private fun dfs(symbol: DataFlowIR.FunctionSymbol) {
|
||||
val resolvedFunctionSymbol = symbol.resolved()
|
||||
if (resolvedFunctionSymbol is DataFlowIR.FunctionSymbol.External) {
|
||||
|
||||
DEBUG_OUTPUT(1) { println("Function $resolvedFunctionSymbol is external") }
|
||||
|
||||
val resolvedReturnType = returnType.resolved()
|
||||
val resolvedReturnType = symbol.returnType.resolved()
|
||||
if (resolvedReturnType.isFinal) {
|
||||
|
||||
DEBUG_OUTPUT(1) { println("Adding return type as it is final") }
|
||||
@@ -342,25 +340,25 @@ internal object Devirtualization {
|
||||
nodeLoop@for (node in function.body.nodes) {
|
||||
when (node) {
|
||||
is DataFlowIR.Node.NewObject -> {
|
||||
addInstantiatingClass(node.returnType)
|
||||
dfs(node.callee, node.returnType)
|
||||
addInstantiatingClass(node.constructedType)
|
||||
dfs(node.callee)
|
||||
}
|
||||
|
||||
is DataFlowIR.Node.Singleton -> {
|
||||
addInstantiatingClass(node.type)
|
||||
node.constructor?.let { dfs(it, node.type) }
|
||||
node.constructor?.let { dfs(it) }
|
||||
}
|
||||
|
||||
is DataFlowIR.Node.Const -> addInstantiatingClass(node.type)
|
||||
|
||||
is DataFlowIR.Node.StaticCall ->
|
||||
dfs(node.callee, node.returnType)
|
||||
dfs(node.callee)
|
||||
|
||||
is DataFlowIR.Node.VirtualCall -> {
|
||||
if (node.receiverType == DataFlowIR.Type.Virtual)
|
||||
continue@nodeLoop
|
||||
val receiverType = node.receiverType.resolved()
|
||||
val vCallReturnType = node.returnType.resolved()
|
||||
val vCallReturnType = node.callee.returnType.resolved()
|
||||
|
||||
DEBUG_OUTPUT(1) {
|
||||
println("Adding virtual callsite:")
|
||||
@@ -399,7 +397,7 @@ internal object Devirtualization {
|
||||
val rootSet = computeRootSet(context, moduleDFG, externalModulesDFG)
|
||||
|
||||
val instantiatingClasses =
|
||||
InstantiationsSearcher(functions, rootSet, typeHierarchy).search()
|
||||
InstantiationsSearcher(rootSet, typeHierarchy).search()
|
||||
.withIndex()
|
||||
.associate { it.value to (it.index + 1 /* 0 is reserved for [DataFlowIR.Type.Virtual] */) }
|
||||
val allTypes = listOf(DataFlowIR.Type.Virtual) + instantiatingClasses.asSequence().sortedBy { it.value }.map { it.key }
|
||||
@@ -531,7 +529,7 @@ internal object Devirtualization {
|
||||
if (virtualCallSiteReceivers == null || virtualCallSiteReceivers.receiver.types[VIRTUAL_TYPE_ID]) {
|
||||
|
||||
DEBUG_OUTPUT(0) {
|
||||
println("Unable to devirtualize callsite ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }")
|
||||
println("Unable to devirtualize callsite ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }")
|
||||
println(" receiver is Virtual")
|
||||
}
|
||||
|
||||
@@ -542,16 +540,16 @@ internal object Devirtualization {
|
||||
.map { it.value }
|
||||
.filter { it != nothing }
|
||||
val map = virtualCallSiteReceivers.devirtualizedCallees.associateBy({ it.receiverType }, { it })
|
||||
result[virtualCall] = DevirtualizedCallSite(possibleReceivers.map { receiverType ->
|
||||
result[virtualCall] = DevirtualizedCallSite(virtualCall.callee.resolved(), possibleReceivers.map { receiverType ->
|
||||
assert (map[receiverType] != null) {
|
||||
"Non-expected receiver type $receiverType at call site: " +
|
||||
(virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString())
|
||||
(virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString())
|
||||
}
|
||||
val devirtualizedCallee = map[receiverType]!!
|
||||
val callee = devirtualizedCallee.callee
|
||||
if (callee is DataFlowIR.FunctionSymbol.Declared && callee.symbolTableIndex < 0)
|
||||
error("Function ${devirtualizedCallee.receiverType}.$callee cannot be called virtually," +
|
||||
" but actually is at call site: ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }")
|
||||
" but actually is at call site: ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString() }")
|
||||
devirtualizedCallee
|
||||
}) to virtualCallSiteReceivers.caller
|
||||
}
|
||||
@@ -559,10 +557,10 @@ internal object Devirtualization {
|
||||
DEBUG_OUTPUT(0) {
|
||||
println("Devirtualized from current module:")
|
||||
result.forEach { virtualCall, devirtualizedCallSite ->
|
||||
if (virtualCall.callSite != null) {
|
||||
if (virtualCall.irCallSite != null) {
|
||||
println("DEVIRTUALIZED")
|
||||
println("FUNCTION: ${devirtualizedCallSite.second}")
|
||||
println("CALL SITE: ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}")
|
||||
println("CALL SITE: ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}")
|
||||
println("POSSIBLE RECEIVERS:")
|
||||
devirtualizedCallSite.first.possibleCallees.forEach { println(" TYPE: ${it.receiverType}") }
|
||||
devirtualizedCallSite.first.possibleCallees.forEach { println(" FUN: ${it.callee}") }
|
||||
@@ -571,10 +569,10 @@ internal object Devirtualization {
|
||||
}
|
||||
println("Devirtualized from external modules:")
|
||||
result.forEach { virtualCall, devirtualizedCallSite ->
|
||||
if (virtualCall.callSite == null) {
|
||||
if (virtualCall.irCallSite == null) {
|
||||
println("DEVIRTUALIZED")
|
||||
println("FUNCTION: ${devirtualizedCallSite.second}")
|
||||
println("CALL SITE: ${virtualCall.callSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}")
|
||||
println("CALL SITE: ${virtualCall.irCallSite?.let { ir2stringWhole(it) } ?: virtualCall.toString()}")
|
||||
println("POSSIBLE RECEIVERS:")
|
||||
devirtualizedCallSite.first.possibleCallees.forEach { println(" TYPE: ${it.receiverType}") }
|
||||
devirtualizedCallSite.first.possibleCallees.forEach { println(" FUN: ${it.callee}") }
|
||||
@@ -647,11 +645,10 @@ internal object Devirtualization {
|
||||
if (symbol is DataFlowIR.FunctionSymbol.External) return null
|
||||
constraintGraph.functions[symbol]?.let { return it }
|
||||
|
||||
val function = functions[symbol] ?: error("Unknown function: $symbol")
|
||||
val parameters = Array(symbol.numberOfParameters) { ordinaryNode { "Param#$it\$$symbol" } }
|
||||
val parameters = Array(symbol.parameterTypes.size) { ordinaryNode { "Param#$it\$$symbol" } }
|
||||
if (isRoot) {
|
||||
// Exported function from the current module.
|
||||
function.parameterTypes.forEachIndexed { index, type ->
|
||||
symbol.parameterTypes.forEachIndexed { index, type ->
|
||||
val resolvedType = type.resolved()
|
||||
val node = if (!resolvedType.isFinal)
|
||||
constraintGraph.virtualNode
|
||||
@@ -769,10 +766,10 @@ internal object Devirtualization {
|
||||
function.parameters[node.index]
|
||||
|
||||
is DataFlowIR.Node.StaticCall ->
|
||||
doCall(node.callee, node.arguments, node.returnType.resolved(), node.receiverType?.resolved())
|
||||
doCall(node.callee, node.arguments, node.callee.returnType.resolved(), node.receiverType?.resolved())
|
||||
|
||||
is DataFlowIR.Node.NewObject -> {
|
||||
val returnType = node.returnType.resolved()
|
||||
val returnType = node.constructedType.resolved()
|
||||
val instanceNode = concreteClass(returnType)
|
||||
doCall(node.callee, listOf(instanceNode) + node.arguments, returnType, null)
|
||||
instanceNode
|
||||
@@ -812,7 +809,7 @@ internal object Devirtualization {
|
||||
println()
|
||||
}
|
||||
|
||||
val returnType = node.returnType.resolved()
|
||||
val returnType = node.callee.returnType.resolved()
|
||||
val receiverNode = edgeToConstraintNode(node.arguments[0])
|
||||
if (receiverType == DataFlowIR.Type.Virtual)
|
||||
constraintGraph.virtualNode.addEdge(receiverNode)
|
||||
@@ -891,7 +888,7 @@ internal object Devirtualization {
|
||||
|
||||
class DevirtualizedCallee(val receiverType: DataFlowIR.Type, val callee: DataFlowIR.FunctionSymbol)
|
||||
|
||||
class DevirtualizedCallSite(val possibleCallees: List<DevirtualizedCallee>)
|
||||
class DevirtualizedCallSite(val callee: DataFlowIR.FunctionSymbol, val possibleCallees: List<DevirtualizedCallee>)
|
||||
|
||||
class AnalysisResult(val devirtualizedCallSites: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite>)
|
||||
|
||||
@@ -901,8 +898,8 @@ internal object Devirtualization {
|
||||
val devirtualizedCallSites =
|
||||
devirtualizationAnalysisResult
|
||||
.asSequence()
|
||||
.filter { it.key.callSite != null }
|
||||
.associate { it.key.callSite!! to it.value }
|
||||
.filter { it.key.irCallSite != null }
|
||||
.associate { it.key.irCallSite!! to it.value }
|
||||
Devirtualization.devirtualize(irModule, context, devirtualizedCallSites)
|
||||
return AnalysisResult(devirtualizationAnalysisResult)
|
||||
}
|
||||
|
||||
+4
-4
@@ -266,7 +266,7 @@ internal object EscapeAnalysis {
|
||||
}
|
||||
|
||||
for (functionSymbol in callGraph.directEdges.keys) {
|
||||
val numberOfParameters = intraproceduralAnalysisResult[functionSymbol]!!.function.parameterTypes.size
|
||||
val numberOfParameters = functionSymbol.parameterTypes.size
|
||||
escapeAnalysisResults[functionSymbol] = FunctionEscapeAnalysisResult(
|
||||
// Assume no edges at the beginning.
|
||||
// Then iteratively add needed.
|
||||
@@ -321,7 +321,7 @@ internal object EscapeAnalysis {
|
||||
for (graph in pointsToGraphs.values) {
|
||||
graph.nodes.keys
|
||||
.filterIsInstance<DataFlowIR.Node.Call>()
|
||||
.forEach { call -> call.callSite?.let { lifetimes.put(it, graph.lifetimeOf(call)) } }
|
||||
.forEach { call -> call.irCallSite?.let { lifetimes.put(it, graph.lifetimeOf(call)) } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ internal object EscapeAnalysis {
|
||||
}
|
||||
|
||||
private fun getConservativeFunctionEAResult(symbol: DataFlowIR.FunctionSymbol): FunctionEscapeAnalysisResult {
|
||||
val numberOfParameters = symbol.numberOfParameters
|
||||
val numberOfParameters = symbol.parameterTypes.size
|
||||
return FunctionEscapeAnalysisResult((0..numberOfParameters).map {
|
||||
ParameterEscapeAnalysisResult(
|
||||
escapes = true,
|
||||
@@ -378,7 +378,7 @@ internal object EscapeAnalysis {
|
||||
|
||||
FunctionEscapeAnalysisResult.fromBits(
|
||||
callee.escapes ?: 0,
|
||||
(0..callee.numberOfParameters).map { callee.pointsTo?.elementAtOrNull(it) ?: 0 }
|
||||
(0..callee.parameterTypes.size).map { callee.pointsTo?.elementAtOrNull(it) ?: 0 }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user