[EE-IR] Support Local Functions

This commit introduces support for calling and referencing local functions and
objects in evaluate expression on the IR backend.

The primary incision is a lowering inserted after Local Declaration Lowering,
that uses the intermediate data structures recorded by LDL to rewrite calls to
local functions to the appropriate function in the binary, instead of predicting
the compilation strategy. The required changes to the rest of the pipeline
facilitate piping the required data around.

The key to this transformation is that _captures by the local function_ must be
introduced as _captures by the fragment function_, such that the evaluator
infrastructure can find the appropriate values at run-time. This is necessary
due to the strategy of compiling local functions to static functions instead of
closures.

Additional test coverage of stepping behavior support the corresponding changes
in the Evaluator, part of the Kotlin Debugger plug-in.
This commit is contained in:
Kristoffer Andersen
2022-01-17 16:59:25 +01:00
committed by Nikita Nazarov
parent 5af9303a16
commit 4f8ef8c315
21 changed files with 575 additions and 56 deletions
@@ -11,9 +11,9 @@ import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.lower.inline.isInlineParameter
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
@@ -71,7 +71,8 @@ class LocalDeclarationsLowering(
val localNameSanitizer: (String) -> String = { it },
val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT,
val suggestUniqueNames: Boolean = true, // When `true` appends a `-#index` suffix to lifted declaration names
val forceFieldsForInlineCaptures: Boolean = false // See `LocalClassContext`
val forceFieldsForInlineCaptures: Boolean = false, // See `LocalClassContext`
private val postLocalDeclarationLoweringCallback: ((IntermediateDatastructures) -> Unit)? = null
) :
BodyLoweringPass {
@@ -109,7 +110,7 @@ class LocalDeclarationsLowering(
ScopeWithCounter(this)
}
private abstract class LocalContext {
abstract class LocalContext {
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
// By the time typeRemapper is used, the map will be already filled
@@ -121,7 +122,7 @@ class LocalDeclarationsLowering(
abstract fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression?
}
private abstract class LocalContextWithClosureAsParameters : LocalContext() {
abstract class LocalContextWithClosureAsParameters : LocalContext() {
abstract val declaration: IrFunction
abstract val transformedDeclaration: IrFunction
@@ -135,7 +136,7 @@ class LocalDeclarationsLowering(
}
}
private class LocalFunctionContext(
class LocalFunctionContext(
override val declaration: IrSimpleFunction,
val index: Int,
val ownerForLoweredDeclaration: IrDeclarationContainer
@@ -246,6 +247,10 @@ class LocalDeclarationsLowering(
rewriteDeclarations()
insertLoweredDeclarationForLocalFunctions()
postLocalDeclarationLoweringCallback?.invoke(
IntermediateDatastructures(localFunctions, newParameterToOld, newParameterToCaptured)
)
}
private fun insertLoweredDeclarationForLocalFunctions() {
@@ -967,6 +972,12 @@ class LocalDeclarationsLowering(
}, Data(null, false))
}
}
data class IntermediateDatastructures(
val localFunctions: Map<IrFunction, LocalFunctionContext>,
val newParameterToOld: Map<IrValueParameter, IrValueParameter>,
val newParameterToCaptured: Map<IrValueParameter, IrValueSymbol>
)
}
// Local inner classes capture anything through outer