01c16ed736
^KT-64570
95 lines
3.5 KiB
Markdown
95 lines
3.5 KiB
Markdown
# Basic step-by-step inlining example for proposed model
|
|
|
|
Let's check the following code:
|
|
```kotlin
|
|
// lib
|
|
fun process(x: Int) { /* some code here */ }
|
|
inline fun run(block: () -> Int) = process(block())
|
|
// main
|
|
fun foo() {
|
|
run { 42 }
|
|
}
|
|
```
|
|
|
|
We would dig deeper into the compilation of the main module, assuming lib is already compiled.
|
|
|
|
|
|
After frontend execution, we get something like that. Here we have all calls resolved.
|
|
Functions from dependencies (lib) are loaded as LazyIr.
|
|
|
|
```kotlin
|
|
fun foo() : Unit {
|
|
run(
|
|
lambda@{ return@lambda 42 }
|
|
)
|
|
}
|
|
|
|
// dependencies:
|
|
// lazyIR without bodies
|
|
fun process(x: Int): Unit
|
|
inline fun run(block: Function0<Int>)
|
|
// ... lazyIR for Int, Unit, Function and so on
|
|
```
|
|
|
|
Then, pre-inline lowering happens. But as we have a very simple example, there is nothing to do.
|
|
|
|
Next, we need to load Ir of run function. For that we need to run Deserializer. But we can't run linker,
|
|
so references inside function body wouldn't be resolved.
|
|
|
|
```kotlin
|
|
// IrFunction
|
|
// name = run
|
|
// isInline = true
|
|
// valueParameter0
|
|
// irType
|
|
// classifier = Lazy class kotlin.Function0 (from Lazy run function)
|
|
// typeArgument0 = Lazy class kotlin.Int (from Lazy run function)
|
|
// returnType = Lazy class kotlin.Unit (from Lazy run function)
|
|
// body
|
|
// IrCall symbol = Unbound function symbol with signature "process(Int) : Unit"
|
|
// returnType = IrType classifier = Unbound class symbol with singnature kotlin.Unit
|
|
// valueArgument0 =
|
|
// IrCall symbol = Unbound function symbol with signature Function0.invoke()
|
|
// typeArgument0 = IrType classifier = Unbound class symbol with singnature kotlin.Int
|
|
// valueArguemnt0 = IrGet valueParamenter block
|
|
// type = Unbound class symbol with singnature kotlin.Int
|
|
//
|
|
inline fun run(block: Function0<Int>) : Unit { // note, that here we merged LazyIr of run function with deserialized body
|
|
process(block.invoke())
|
|
}
|
|
```
|
|
|
|
Now this function can be inlined to original.
|
|
|
|
```kotlin
|
|
// IrFunction
|
|
// name = foo
|
|
// returnType = Lazy class kotlin.Unit
|
|
// body
|
|
// IrReturnableBlock symbol=symbol1
|
|
// type = Lazy class kotlin.Unit
|
|
// IrInlinedFunctionBlock required for debug information
|
|
// IrReturn
|
|
// target=symbol1
|
|
// value = IrCall
|
|
// symbol = Unbound function symbol with signature "process(Int) : Unit"
|
|
// returnType = IrType classifier = Unbound class symbol with singnature kotlin.Unit
|
|
// valueArgument0
|
|
// IrReturnableBlock symbol=symbol2
|
|
// type = Lazy class for kotlin.Int
|
|
// IrInlinedFunctionBlock required for debug information
|
|
// IrReturn target=symbol2 value = IrConst<Int>(42)
|
|
fun foo() : Unit {
|
|
inlinedBlock@{
|
|
return@inlinedBlock process(lambda@ { return@lambda 42 })
|
|
}
|
|
}
|
|
```
|
|
|
|
Several side notes on the result:
|
|
1. We have both lazy references to kotlin.Unit/kotlin.Int and unbound ones in the tree now.
|
|
It is fine, as we only need to deserialize it now.
|
|
2. While inlining we need to understand that we need special handling of
|
|
`Unbound function symbol with signature Function0.invoke()`, this must be done by signature only.
|
|
3. IrReturnableBlock is represented like it works now, while IrInlinedFunctionBlock is significantly simplified.
|
|
Probably we need to redesign both to make them serializable. |