JVM_IR: Generate fake inlining local variables for debugging.
This commit is contained in:
@@ -291,6 +291,7 @@ private val jvmFilePhases =
|
|||||||
checkLocalNamesWithOldBackendPhase then
|
checkLocalNamesWithOldBackendPhase then
|
||||||
|
|
||||||
mainMethodGenerationPhase then
|
mainMethodGenerationPhase then
|
||||||
|
fakeInliningLocalVariablesLowering then
|
||||||
|
|
||||||
makePatchParentsPhase(3)
|
makePatchParentsPhase(3)
|
||||||
|
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.codegen.mapClass
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
|
||||||
|
internal val fakeInliningLocalVariablesLowering = makeIrFilePhase(
|
||||||
|
::FakeInliningLocalVariablesLowering,
|
||||||
|
name = "FakeInliningLocalVariablesLowering",
|
||||||
|
description = "Add fake locals to identify the range of inlined functions and lambdas"
|
||||||
|
)
|
||||||
|
|
||||||
|
internal class FakeInliningLocalVariablesLowering(val context: JvmBackendContext) : IrElementVisitorVoid, FileLoweringPass {
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall) {
|
||||||
|
expression.acceptChildrenVoid(this)
|
||||||
|
val callee = expression.symbol.owner
|
||||||
|
if (callee.isInline) {
|
||||||
|
for (i in 0 until expression.valueArgumentsCount) {
|
||||||
|
val argument = expression.getValueArgument(i)
|
||||||
|
if ((argument is IrBlock) && argument.origin == IrStatementOrigin.LAMBDA) {
|
||||||
|
val lastStatement = argument.statements.last()
|
||||||
|
if (lastStatement is IrFunctionReference) {
|
||||||
|
val localFunForLambda = lastStatement.symbol.owner
|
||||||
|
if (localFunForLambda.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA) {
|
||||||
|
localFunForLambda.addFakeInliningLocalVariablesForArguments(callee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
if (declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null) {
|
||||||
|
declaration.addFakeInliningLocalVariables()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.addFakeInliningLocalVariables() {
|
||||||
|
val currentFunctionName = context.methodSignatureMapper.mapFunctionName(this)
|
||||||
|
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION}$currentFunctionName"
|
||||||
|
addFakeLocalVariable(localName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.addFakeInliningLocalVariablesForArguments(callee: IrFunction) {
|
||||||
|
val currentFunctionName = context.methodSignatureMapper.mapFunctionName(this)
|
||||||
|
val argumentToFunctionName = context.methodSignatureMapper.mapFunctionName(callee)
|
||||||
|
val internalName = context.typeMapper.mapClass(parentAsClass).internalName
|
||||||
|
val thisType = internalName.substringAfterLast('/', internalName)
|
||||||
|
val lambdaReference = "$thisType\$$currentFunctionName"
|
||||||
|
val localName = "${JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT}-$argumentToFunctionName-$lambdaReference"
|
||||||
|
addFakeLocalVariable(localName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.addFakeLocalVariable(name: String) {
|
||||||
|
context.createIrBuilder(symbol).run {
|
||||||
|
body = irBlockBody {
|
||||||
|
// Create temporary variable, but make sure it's origin is `DEFINED` so that
|
||||||
|
// it will materialize in the code.
|
||||||
|
createTmpVariable(irInt(0), name, origin = IrDeclarationOrigin.DEFINED)
|
||||||
|
if (body is IrExpressionBody) {
|
||||||
|
+(body as IrExpressionBody).expression
|
||||||
|
} else {
|
||||||
|
(body as IrBlockBody).statements.forEach { +it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
inline fun <R, T> foo(x : R, y : R, block : (R, R) -> T) : T {
|
inline fun <R, T> foo(x : R, y : R, block : (R, R) -> T) : T {
|
||||||
return block(x, y)
|
return block(x, y)
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun test() {
|
fun test() {
|
||||||
val a = inlineFunInt { 1 }
|
val a = inlineFunInt { 1 }
|
||||||
val b = simpleFunInt { 1 }
|
val b = simpleFunInt { 1 }
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
interface ApplicationCall
|
interface ApplicationCall
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
fun box() {
|
fun box() {
|
||||||
lookAtMe {
|
lookAtMe {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
inline fun <reified T> foo(default: T): T {
|
inline fun <reified T> foo(default: T): T {
|
||||||
var t: T
|
var t: T
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
inline fun bar(x: Int) : Int {
|
inline fun bar(x: Int) : Int {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-3
@@ -30,15 +30,25 @@ abstract class AbstractIrCheckLocalVariablesTableTest : AbstractCheckLocalVariab
|
|||||||
|
|
||||||
private fun getActualVariablesAsList(list: List<LocalVariable>): List<String> {
|
private fun getActualVariablesAsList(list: List<LocalVariable>): List<String> {
|
||||||
return list.map { it.toString() }
|
return list.map { it.toString() }
|
||||||
.map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } // Ignore index
|
// Ignore local index.
|
||||||
|
.map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") }
|
||||||
|
// Ignore the names of local functions which have integer names in
|
||||||
|
// the current backend and more descriptive names with the JVM_IR
|
||||||
|
// backend.
|
||||||
|
.map { line -> line.replace("\\\$\\d+".toRegex(), "\\\$*") }
|
||||||
|
.map { line -> line.replace("\\\$lambda-\\d+".toRegex(), "\\\$*") }
|
||||||
.sorted()
|
.sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getExpectedVariablesAsList(testFile: File): List<String> {
|
private fun getExpectedVariablesAsList(testFile: File): List<String> {
|
||||||
return testFile.readLines()
|
return testFile.readLines()
|
||||||
.filter { line -> line.startsWith("// VARIABLE ") }
|
.filter { line -> line.startsWith("// VARIABLE ") }
|
||||||
.filter { !it.contains("NAME=\$i\$") }
|
// Ignore local index.
|
||||||
.map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") } // Ignore index
|
.map { line -> line.replaceFirst("INDEX=\\d+".toRegex(), "INDEX=*") }
|
||||||
|
// Ignore the names of local functions which have integer names in
|
||||||
|
// the current backend and more descriptive names with the JVM_IR
|
||||||
|
// backend.
|
||||||
|
.map { line -> line.replace("\\\$\\d+".toRegex(), "\\\$*") }
|
||||||
.sorted()
|
.sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user