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 thrownValues = mutableListOf<IrExpression>()
val catchParameters = mutableSetOf<VariableDescriptor>() val catchParameters = mutableSetOf<VariableDescriptor>()
private val returnableBlocks = mutableMapOf<FunctionDescriptor, IrReturnableBlock>()
private val suspendableExpressionStack = mutableListOf<IrSuspendableExpression>() private val suspendableExpressionStack = mutableListOf<IrSuspendableExpression>()
override fun visitElement(element: IrElement) { 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 arrayGetSymbol = context.ir.symbols.arrayGet
private val arraySetSymbol = context.ir.symbols.arraySet 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 scheduleImplSymbol = context.ir.symbols.scheduleImpl
private val scheduleImplProducerClassSymbol = context.ir.symbols.functions[0] private val scheduleImplProducerClassSymbol = context.ir.symbols.functions[0]
private val scheduleImplProducerParam = scheduleImplSymbol.descriptor.valueParameters[2].also { 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 allParameters = (descriptor as? FunctionDescriptor)?.allParameters ?: emptyList()
private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) }) private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) })
private val continuationParameter = if (descriptor !is IrSimpleFunction) { private val continuationParameter = when {
null descriptor !is IrSimpleFunction -> null
} else if (descriptor.isSuspend) {
DataFlowIR.Node.Parameter(allParameters.size) 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. doResumeFunctionSymbol in descriptor.overriddenSymbols -> // <this> is a CoroutineImpl inheritor.
} else { templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
null
else -> null
} }
private fun getContinuation() = continuationParameter ?: error("Function $descriptor has no continuation parameter") 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!!), arraySetSymbol -> DataFlowIR.Node.ArrayWrite(expressionToEdge(value.dispatchReceiver!!),
expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!)) 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 -> { else -> {
val callee = value.symbol.owner val callee = value.symbol.owner
val arguments = value.getArguments() 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) { class FieldRead(val receiver: Edge?, val field: Field) {
constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data)) constructor(data: ArraySlice) : this(data.readNullable { Edge(this) }, Field(data))
@@ -578,6 +587,7 @@ internal object DFGSerializer {
VTABLE_CALL, VTABLE_CALL,
ITABLE_CALL, ITABLE_CALL,
SINGLETON, SINGLETON,
ALLOC_INSTANCE,
FIELD_READ, FIELD_READ,
FIELD_WRITE, FIELD_WRITE,
ARRAY_READ, ARRAY_READ,
@@ -586,49 +596,52 @@ internal object DFGSerializer {
} }
class Node { class Node {
var parameter : Parameter? = null var parameter : Parameter? = null
var const : Const? = null var const : Const? = null
var staticCall : StaticCall? = null var staticCall : StaticCall? = null
var newObject : NewObject? = null var newObject : NewObject? = null
var vtableCall : VtableCall? = null var vtableCall : VtableCall? = null
var itableCall : ItableCall? = null var itableCall : ItableCall? = null
var singleton : Singleton? = null var singleton : Singleton? = null
var fieldRead : FieldRead? = null var allocInstance: AllocInstance? = null
var fieldWrite : FieldWrite? = null var fieldRead : FieldRead? = null
var arrayRead : ArrayRead? = null var fieldWrite : FieldWrite? = null
var arrayWrite : ArrayWrite? = null var arrayRead : ArrayRead? = null
var variable : Variable? = null var arrayWrite : ArrayWrite? = null
var variable : Variable? = null
val type get() = when { val type get() = when {
parameter != null -> NodeType.PARAMETER parameter != null -> NodeType.PARAMETER
const != null -> NodeType.CONST const != null -> NodeType.CONST
staticCall != null -> NodeType.STATIC_CALL staticCall != null -> NodeType.STATIC_CALL
newObject != null -> NodeType.NEW_OBJECT newObject != null -> NodeType.NEW_OBJECT
vtableCall != null -> NodeType.VTABLE_CALL vtableCall != null -> NodeType.VTABLE_CALL
itableCall != null -> NodeType.ITABLE_CALL itableCall != null -> NodeType.ITABLE_CALL
singleton != null -> NodeType.SINGLETON singleton != null -> NodeType.SINGLETON
fieldRead != null -> NodeType.FIELD_READ allocInstance != null -> NodeType.ALLOC_INSTANCE
fieldWrite != null -> NodeType.FIELD_WRITE fieldRead != null -> NodeType.FIELD_READ
arrayRead != null -> NodeType.ARRAY_READ fieldWrite != null -> NodeType.FIELD_WRITE
arrayWrite != null -> NodeType.ARRAY_WRITE arrayRead != null -> NodeType.ARRAY_READ
variable != null -> NodeType.VARIABLE arrayWrite != null -> NodeType.ARRAY_WRITE
else -> NodeType.UNKNOWN variable != null -> NodeType.VARIABLE
else -> NodeType.UNKNOWN
} }
fun write(result: ArraySlice) { fun write(result: ArraySlice) {
result.writeByte(type.ordinal.toByte()) result.writeByte(type.ordinal.toByte())
parameter ?.write(result) parameter ?.write(result)
const ?.write(result) const ?.write(result)
staticCall?.write(result) staticCall ?.write(result)
newObject ?.write(result) newObject ?.write(result)
vtableCall?.write(result) vtableCall ?.write(result)
itableCall?.write(result) itableCall ?.write(result)
singleton ?.write(result) singleton ?.write(result)
fieldRead ?.write(result) allocInstance?.write(result)
fieldWrite?.write(result) fieldRead ?.write(result)
arrayRead ?.write(result) fieldWrite ?.write(result)
arrayWrite?.write(result) arrayRead ?.write(result)
variable ?.write(result) arrayWrite ?.write(result)
variable ?.write(result)
} }
companion object { companion object {
@@ -653,6 +666,9 @@ internal object DFGSerializer {
fun singleton(type: Int, constructor: Int?) = fun singleton(type: Int, constructor: Int?) =
Node().also { it.singleton = Singleton(type, constructor) } Node().also { it.singleton = Singleton(type, constructor) }
fun allocInst(type: Int) =
Node().also { it.allocInstance = AllocInstance(type) }
fun fieldRead(receiver: Edge?, field: Field) = fun fieldRead(receiver: Edge?, field: Field) =
Node().also { it.fieldRead = FieldRead(receiver, field) } Node().also { it.fieldRead = FieldRead(receiver, field) }
@@ -672,19 +688,20 @@ internal object DFGSerializer {
val type = enumValues<NodeType>()[data.readByte().toInt()] val type = enumValues<NodeType>()[data.readByte().toInt()]
val result = Node() val result = Node()
when (type) { when (type) {
NodeType.PARAMETER -> result.parameter = Parameter (data) NodeType.PARAMETER -> result.parameter = Parameter (data)
NodeType.CONST -> result.const = Const (data) NodeType.CONST -> result.const = Const (data)
NodeType.STATIC_CALL -> result.staticCall = StaticCall(data) NodeType.STATIC_CALL -> result.staticCall = StaticCall (data)
NodeType.NEW_OBJECT -> result.newObject = NewObject (data) NodeType.NEW_OBJECT -> result.newObject = NewObject (data)
NodeType.VTABLE_CALL -> result.vtableCall = VtableCall(data) NodeType.VTABLE_CALL -> result.vtableCall = VtableCall (data)
NodeType.ITABLE_CALL -> result.itableCall = ItableCall(data) NodeType.ITABLE_CALL -> result.itableCall = ItableCall (data)
NodeType.SINGLETON -> result.singleton = Singleton (data) NodeType.SINGLETON -> result.singleton = Singleton (data)
NodeType.FIELD_READ -> result.fieldRead = FieldRead (data) NodeType.ALLOC_INSTANCE -> result.allocInstance = AllocInstance(data)
NodeType.FIELD_WRITE -> result.fieldWrite = FieldWrite(data) NodeType.FIELD_READ -> result.fieldRead = FieldRead (data)
NodeType.ARRAY_READ -> result.arrayRead = ArrayRead (data) NodeType.FIELD_WRITE -> result.fieldWrite = FieldWrite (data)
NodeType.ARRAY_WRITE -> result.arrayWrite = ArrayWrite(data) NodeType.ARRAY_READ -> result.arrayRead = ArrayRead (data)
NodeType.VARIABLE -> result.variable = Variable (data) NodeType.ARRAY_WRITE -> result.arrayWrite = ArrayWrite (data)
else -> { } NodeType.VARIABLE -> result.variable = Variable (data)
else -> { }
} }
return result return result
} }
@@ -873,6 +890,9 @@ internal object DFGSerializer {
is DataFlowIR.Node.Singleton -> is DataFlowIR.Node.Singleton ->
Node.singleton(typeMap[node.type]!!, node.constructor?.let { functionSymbolMap[it]!! }) Node.singleton(typeMap[node.type]!!, node.constructor?.let { functionSymbolMap[it]!! })
is DataFlowIR.Node.AllocInstance ->
Node.allocInst(typeMap[node.type]!!)
is DataFlowIR.Node.FieldRead -> is DataFlowIR.Node.FieldRead ->
Node.fieldRead(node.receiver?.let { buildEdge(it) }, buildField(node.field)) 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] }) DataFlowIR.Node.Singleton(types[singleton.type], singleton.constructor?.let { functionSymbols[it] })
} }
NodeType.ALLOC_INSTANCE -> {
DataFlowIR.Node.AllocInstance(types[it.allocInstance!!.type])
}
NodeType.FIELD_READ -> { NodeType.FIELD_READ -> {
val fieldRead = it.fieldRead!! val fieldRead = it.fieldRead!!
val receiver = fieldRead.receiver?.let { deserializeEdge(it) } val receiver = fieldRead.receiver?.let { deserializeEdge(it) }
@@ -237,6 +237,7 @@ internal object DataFlowIR {
val receiverType: Type?, irCallSite: IrFunctionAccessExpression?) val receiverType: Type?, irCallSite: IrFunctionAccessExpression?)
: Call(callee, arguments, irCallSite) : 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?) class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type, override val irCallSite: IrCall?)
: Call(constructor, arguments, irCallSite) : Call(constructor, arguments, irCallSite)
@@ -254,6 +255,8 @@ internal object DataFlowIR {
class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node() 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 FieldRead(val receiver: Edge?, val field: Field, val ir: IrGetField?) : Node()
class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node() class FieldWrite(val receiver: Edge?, val field: Field, val value: Edge) : Node()
@@ -296,6 +299,9 @@ internal object DataFlowIR {
is Node.Singleton -> is Node.Singleton ->
" SINGLETON ${node.type}\n" " SINGLETON ${node.type}\n"
is Node.AllocInstance ->
" ALLOC INSTANCE ${node.type}\n"
is Node.StaticCall -> { is Node.StaticCall -> {
val result = StringBuilder() val result = StringBuilder()
result.appendln(" STATIC CALL ${node.callee}") result.appendln(" STATIC CALL ${node.callee}")
@@ -355,6 +355,10 @@ internal object Devirtualization {
node.constructor?.let { dfs(it) } node.constructor?.let { dfs(it) }
} }
is DataFlowIR.Node.AllocInstance -> {
addInstantiatingClass(node.type)
}
is DataFlowIR.Node.Const -> addInstantiatingClass(node.type) is DataFlowIR.Node.Const -> addInstantiatingClass(node.type)
is DataFlowIR.Node.StaticCall -> is DataFlowIR.Node.StaticCall ->
@@ -918,6 +922,10 @@ internal object Devirtualization {
instanceNode instanceNode
} }
is DataFlowIR.Node.AllocInstance -> {
concreteClass(node.type.resolved())
}
is DataFlowIR.Node.FieldRead -> is DataFlowIR.Node.FieldRead ->
fieldNode(node.field) fieldNode(node.field)