DFG: Supported createUninitializedInstance/initInstance functions

This commit is contained in:
Igor Chevdar
2018-04-23 19:01:17 +03:00
parent 0d50877d63
commit 3cd290631c
4 changed files with 116 additions and 59 deletions
@@ -355,7 +355,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
val thrownValues = mutableListOf<IrExpression>()
val catchParameters = mutableSetOf<VariableDescriptor>()
private val returnableBlocks = mutableMapOf<FunctionDescriptor, IrReturnableBlock>()
private val suspendableExpressionStack = mutableListOf<IrSuspendableExpression>()
override fun visitElement(element: IrElement) {
@@ -453,6 +452,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private val arrayGetSymbol = context.ir.symbols.arrayGet
private val arraySetSymbol = context.ir.symbols.arraySet
private val createUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance
private val initInstanceSymbol = context.ir.symbols.initInstance
private val scheduleImplSymbol = context.ir.symbols.scheduleImpl
private val scheduleImplProducerClassSymbol = context.ir.symbols.functions[0]
private val scheduleImplProducerParam = scheduleImplSymbol.descriptor.valueParameters[2].also {
@@ -473,14 +474,15 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private val allParameters = (descriptor as? FunctionDescriptor)?.allParameters ?: emptyList()
private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) })
private val continuationParameter = if (descriptor !is IrSimpleFunction) {
null
} else if (descriptor.isSuspend) {
DataFlowIR.Node.Parameter(allParameters.size)
} else if (doResumeFunctionSymbol in descriptor.overriddenSymbols) { // <this> is a CoroutineImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
} else {
null
private val continuationParameter = when {
descriptor !is IrSimpleFunction -> null
descriptor.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size)
doResumeFunctionSymbol in descriptor.overriddenSymbols -> // <this> is a CoroutineImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
else -> null
}
private fun getContinuation() = continuationParameter ?: error("Function $descriptor has no continuation parameter")
@@ -592,6 +594,23 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
arraySetSymbol -> DataFlowIR.Node.ArrayWrite(expressionToEdge(value.dispatchReceiver!!),
expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!))
createUninitializedInstanceSymbol ->
DataFlowIR.Node.AllocInstance(symbolTable.mapType(value.getTypeArgument(0)!!))
initInstanceSymbol -> {
val thiz = expressionToEdge(value.getValueArgument(0)!!)
val initializer = value.getValueArgument(1) as IrCall
val arguments = listOf(thiz) + initializer.getArguments().map { expressionToEdge(it.second) }
val callee = initializer.symbol.owner as IrConstructor
DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(callee),
arguments,
symbolTable.mapClass(context.ir.symbols.unit.owner),
symbolTable.mapClass(callee.constructedClass),
null
)
}
else -> {
val callee = value.symbol.owner
val arguments = value.getArguments()
@@ -516,6 +516,15 @@ internal object DFGSerializer {
}
}
class AllocInstance(val type: Int) {
constructor(data: ArraySlice) : this(data.readInt())
fun write(result: ArraySlice) {
result.writeInt(type)
}
}
class FieldRead(val receiver: Edge?, val field: Field) {
constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data))
@@ -578,6 +587,7 @@ internal object DFGSerializer {
VTABLE_CALL,
ITABLE_CALL,
SINGLETON,
ALLOC_INSTANCE,
FIELD_READ,
FIELD_WRITE,
ARRAY_READ,
@@ -586,49 +596,52 @@ internal object DFGSerializer {
}
class Node {
var parameter : Parameter? = null
var const : Const? = null
var staticCall : StaticCall? = null
var newObject : NewObject? = null
var vtableCall : VtableCall? = null
var itableCall : ItableCall? = null
var singleton : Singleton? = null
var fieldRead : FieldRead? = null
var fieldWrite : FieldWrite? = null
var arrayRead : ArrayRead? = null
var arrayWrite : ArrayWrite? = null
var variable : Variable? = null
var parameter : Parameter? = null
var const : Const? = null
var staticCall : StaticCall? = null
var newObject : NewObject? = null
var vtableCall : VtableCall? = null
var itableCall : ItableCall? = null
var singleton : Singleton? = null
var allocInstance: AllocInstance? = null
var fieldRead : FieldRead? = null
var fieldWrite : FieldWrite? = null
var arrayRead : ArrayRead? = null
var arrayWrite : ArrayWrite? = null
var variable : Variable? = null
val type get() = when {
parameter != null -> NodeType.PARAMETER
const != null -> NodeType.CONST
staticCall != null -> NodeType.STATIC_CALL
newObject != null -> NodeType.NEW_OBJECT
vtableCall != null -> NodeType.VTABLE_CALL
itableCall != null -> NodeType.ITABLE_CALL
singleton != null -> NodeType.SINGLETON
fieldRead != null -> NodeType.FIELD_READ
fieldWrite != null -> NodeType.FIELD_WRITE
arrayRead != null -> NodeType.ARRAY_READ
arrayWrite != null -> NodeType.ARRAY_WRITE
variable != null -> NodeType.VARIABLE
else -> NodeType.UNKNOWN
parameter != null -> NodeType.PARAMETER
const != null -> NodeType.CONST
staticCall != null -> NodeType.STATIC_CALL
newObject != null -> NodeType.NEW_OBJECT
vtableCall != null -> NodeType.VTABLE_CALL
itableCall != null -> NodeType.ITABLE_CALL
singleton != null -> NodeType.SINGLETON
allocInstance != null -> NodeType.ALLOC_INSTANCE
fieldRead != null -> NodeType.FIELD_READ
fieldWrite != null -> NodeType.FIELD_WRITE
arrayRead != null -> NodeType.ARRAY_READ
arrayWrite != null -> NodeType.ARRAY_WRITE
variable != null -> NodeType.VARIABLE
else -> NodeType.UNKNOWN
}
fun write(result: ArraySlice) {
result.writeByte(type.ordinal.toByte())
parameter ?.write(result)
const ?.write(result)
staticCall?.write(result)
newObject ?.write(result)
vtableCall?.write(result)
itableCall?.write(result)
singleton ?.write(result)
fieldRead ?.write(result)
fieldWrite?.write(result)
arrayRead ?.write(result)
arrayWrite?.write(result)
variable ?.write(result)
parameter ?.write(result)
const ?.write(result)
staticCall ?.write(result)
newObject ?.write(result)
vtableCall ?.write(result)
itableCall ?.write(result)
singleton ?.write(result)
allocInstance?.write(result)
fieldRead ?.write(result)
fieldWrite ?.write(result)
arrayRead ?.write(result)
arrayWrite ?.write(result)
variable ?.write(result)
}
companion object {
@@ -653,6 +666,9 @@ internal object DFGSerializer {
fun singleton(type: Int, constructor: Int?) =
Node().also { it.singleton = Singleton(type, constructor) }
fun allocInst(type: Int) =
Node().also { it.allocInstance = AllocInstance(type) }
fun fieldRead(receiver: Edge?, field: Field) =
Node().also { it.fieldRead = FieldRead(receiver, field) }
@@ -672,19 +688,20 @@ internal object DFGSerializer {
val type = enumValues<NodeType>()[data.readByte().toInt()]
val result = Node()
when (type) {
NodeType.PARAMETER -> result.parameter = Parameter (data)
NodeType.CONST -> result.const = Const (data)
NodeType.STATIC_CALL -> result.staticCall = StaticCall(data)
NodeType.NEW_OBJECT -> result.newObject = NewObject (data)
NodeType.VTABLE_CALL -> result.vtableCall = VtableCall(data)
NodeType.ITABLE_CALL -> result.itableCall = ItableCall(data)
NodeType.SINGLETON -> result.singleton = Singleton (data)
NodeType.FIELD_READ -> result.fieldRead = FieldRead (data)
NodeType.FIELD_WRITE -> result.fieldWrite = FieldWrite(data)
NodeType.ARRAY_READ -> result.arrayRead = ArrayRead (data)
NodeType.ARRAY_WRITE -> result.arrayWrite = ArrayWrite(data)
NodeType.VARIABLE -> result.variable = Variable (data)
else -> { }
NodeType.PARAMETER -> result.parameter = Parameter (data)
NodeType.CONST -> result.const = Const (data)
NodeType.STATIC_CALL -> result.staticCall = StaticCall (data)
NodeType.NEW_OBJECT -> result.newObject = NewObject (data)
NodeType.VTABLE_CALL -> result.vtableCall = VtableCall (data)
NodeType.ITABLE_CALL -> result.itableCall = ItableCall (data)
NodeType.SINGLETON -> result.singleton = Singleton (data)
NodeType.ALLOC_INSTANCE -> result.allocInstance = AllocInstance(data)
NodeType.FIELD_READ -> result.fieldRead = FieldRead (data)
NodeType.FIELD_WRITE -> result.fieldWrite = FieldWrite (data)
NodeType.ARRAY_READ -> result.arrayRead = ArrayRead (data)
NodeType.ARRAY_WRITE -> result.arrayWrite = ArrayWrite (data)
NodeType.VARIABLE -> result.variable = Variable (data)
else -> { }
}
return result
}
@@ -873,6 +890,9 @@ internal object DFGSerializer {
is DataFlowIR.Node.Singleton ->
Node.singleton(typeMap[node.type]!!, node.constructor?.let { functionSymbolMap[it]!! })
is DataFlowIR.Node.AllocInstance ->
Node.allocInst(typeMap[node.type]!!)
is DataFlowIR.Node.FieldRead ->
Node.fieldRead(node.receiver?.let { buildEdge(it) }, buildField(node.field))
@@ -1108,6 +1128,10 @@ internal object DFGSerializer {
DataFlowIR.Node.Singleton(types[singleton.type], singleton.constructor?.let { functionSymbols[it] })
}
NodeType.ALLOC_INSTANCE -> {
DataFlowIR.Node.AllocInstance(types[it.allocInstance!!.type])
}
NodeType.FIELD_READ -> {
val fieldRead = it.fieldRead!!
val receiver = fieldRead.receiver?.let { deserializeEdge(it) }
@@ -237,6 +237,7 @@ internal object DataFlowIR {
val receiverType: Type?, irCallSite: IrFunctionAccessExpression?)
: Call(callee, arguments, irCallSite)
// TODO: It can be replaced with a pair(AllocInstance, constructor Call), remove.
class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type, override val irCallSite: IrCall?)
: Call(constructor, arguments, irCallSite)
@@ -254,6 +255,8 @@ internal object DataFlowIR {
class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node()
class AllocInstance(val type: Type) : Node()
class FieldRead(val receiver: Edge?, val field: Field, val ir: IrGetField?) : Node()
class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node()
@@ -296,6 +299,9 @@ internal object DataFlowIR {
is Node.Singleton ->
" SINGLETON ${node.type}\n"
is Node.AllocInstance ->
" ALLOC INSTANCE ${node.type}\n"
is Node.StaticCall -> {
val result = StringBuilder()
result.appendln(" STATIC CALL ${node.callee}")
@@ -355,6 +355,10 @@ internal object Devirtualization {
node.constructor?.let { dfs(it) }
}
is DataFlowIR.Node.AllocInstance -> {
addInstantiatingClass(node.type)
}
is DataFlowIR.Node.Const -> addInstantiatingClass(node.type)
is DataFlowIR.Node.StaticCall ->
@@ -918,6 +922,10 @@ internal object Devirtualization {
instanceNode
}
is DataFlowIR.Node.AllocInstance -> {
concreteClass(node.type.resolved())
}
is DataFlowIR.Node.FieldRead ->
fieldNode(node.field)