[JVM] Implement new inlined variable naming format
^KT-65478 fixed
This commit is contained in:
committed by
Alexander Udalov
parent
9ea775cbed
commit
407448d8e3
+18
-6
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.JvmBackendConfig
|
||||
import org.jetbrains.kotlin.codegen.writeKotlinMetadata
|
||||
import org.jetbrains.kotlin.config.JvmAnalysisFlags
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -416,10 +413,25 @@ class ClassCodegen private constructor(
|
||||
)
|
||||
val mv = with(node) { visitor.newMethod(method.descriptorOrigin, access, name, desc, signature, exceptions.toTypedArray()) }
|
||||
val smapCopier = SourceMapCopier(classSMAP, smap)
|
||||
|
||||
val smapCopyingVisitor = object : MethodVisitor(Opcodes.API_VERSION, mv) {
|
||||
override fun visitLineNumber(line: Int, start: Label) =
|
||||
super.visitLineNumber(smapCopier.mapLineNumber(line), start)
|
||||
private val lineNumberMapping = mutableMapOf<Int, Int>()
|
||||
|
||||
override fun visitLineNumber(line: Int, start: Label) {
|
||||
val newLine = smapCopier.mapLineNumber(line)
|
||||
lineNumberMapping[line] = newLine
|
||||
super.visitLineNumber(newLine, start)
|
||||
}
|
||||
|
||||
override fun visitLocalVariable(name: String, descriptor: String, signature: String?, start: Label, end: Label, index: Int) {
|
||||
if (state.configuration.getBoolean(JVMConfigurationKeys.USE_INLINE_SCOPES_NUMBERS) && isFakeLocalVariableForInline(name)) {
|
||||
val newName = updateCallSiteLineNumber(name, lineNumberMapping)
|
||||
return super.visitLocalVariable(newName, descriptor, signature, start, end, index)
|
||||
}
|
||||
super.visitLocalVariable(name, descriptor, signature, start, end, index)
|
||||
}
|
||||
}
|
||||
|
||||
if (method.hasContinuation()) {
|
||||
// Generate a state machine within this method. The continuation class for it should be generated
|
||||
// lazily so that if tail call optimization kicks in, the unused class will not be written to the output.
|
||||
|
||||
+18
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.JvmBackendConfig
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.diagnostics.BackendErrors
|
||||
@@ -50,6 +51,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
@@ -156,6 +158,13 @@ class ExpressionCodegen(
|
||||
val state: GenerationState = context.state
|
||||
val config: JvmBackendConfig = context.config
|
||||
|
||||
override val inlineScopesGenerator =
|
||||
if (state.configuration.getBoolean(JVMConfigurationKeys.USE_INLINE_SCOPES_NUMBERS)) {
|
||||
InlineScopesGenerator()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
override val visitor: InstructionAdapter
|
||||
get() = mv
|
||||
|
||||
@@ -755,6 +764,15 @@ class ExpressionCodegen(
|
||||
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
|
||||
val varType = typeMapper.mapType(declaration)
|
||||
val index = frameMap.enter(declaration.symbol, varType)
|
||||
val name = declaration.name.asString()
|
||||
|
||||
if (state.configuration.getBoolean(JVMConfigurationKeys.USE_INLINE_SCOPES_NUMBERS) &&
|
||||
state.configuration.getBoolean(JVMConfigurationKeys.ENABLE_IR_INLINER) &&
|
||||
isFakeLocalVariableForInline(name) &&
|
||||
name.contains(INLINE_SCOPE_NUMBER_SEPARATOR)
|
||||
) {
|
||||
declaration.name = Name.identifier(updateCallSiteLineNumber(name, lineNumberMapper.getLineNumber()))
|
||||
}
|
||||
|
||||
val initializer = declaration.initializer
|
||||
if (initializer != null) {
|
||||
|
||||
+94
-20
@@ -12,8 +12,9 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.irInlinerIsEnabled
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||
import org.jetbrains.kotlin.codegen.inline.*
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys.USE_INLINE_SCOPES_NUMBERS
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
||||
@@ -21,9 +22,7 @@ import org.jetbrains.kotlin.ir.builders.irInt
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||
import org.jetbrains.kotlin.ir.expressions.IrInlinedFunctionBlock
|
||||
import org.jetbrains.kotlin.ir.util.inlineDeclaration
|
||||
import org.jetbrains.kotlin.ir.util.isFunctionInlining
|
||||
import org.jetbrains.kotlin.ir.util.isLambdaInlining
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -56,8 +55,12 @@ internal class FakeLocalVariablesForIrInlinerLowering(
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.accept(this, null)
|
||||
irFile.acceptVoid(FunctionParametersProcessor())
|
||||
irFile.accept(LocalVariablesProcessor(), LocalVariablesProcessor.Data(processingOriginalDeclarations = false))
|
||||
if (context.configuration.getBoolean(USE_INLINE_SCOPES_NUMBERS)) {
|
||||
irFile.acceptVoid(ScopeNumberVariableProcessor())
|
||||
} else {
|
||||
irFile.acceptVoid(FunctionParametersProcessor())
|
||||
irFile.accept(LocalVariablesProcessor(), LocalVariablesProcessor.Data(processingOriginalDeclarations = false))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
@@ -150,12 +153,16 @@ private class LocalVariablesProcessor : IrElementVisitor<Unit, LocalVariablesPro
|
||||
|
||||
val varName = declaration.name.asString()
|
||||
val varSuffix = when {
|
||||
inlinedStack.size == 1 && !varName.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) -> INLINE_FUN_VAR_SUFFIX
|
||||
else -> ""
|
||||
inlinedStack.size == 1 && !varName.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) ->
|
||||
INLINE_FUN_VAR_SUFFIX
|
||||
else ->
|
||||
""
|
||||
}
|
||||
val newName = when {
|
||||
varSuffix.isNotEmpty() && varName == SpecialNames.THIS.asStringStripSpecialMarkers() -> "this_"
|
||||
else -> varName
|
||||
varSuffix.isNotEmpty() && varName == SpecialNames.THIS.asStringStripSpecialMarkers() ->
|
||||
AsmUtil.INLINE_DECLARATION_SITE_THIS
|
||||
else ->
|
||||
varName
|
||||
}
|
||||
declaration.name = Name.identifier(newName + varSuffix)
|
||||
super.visitVariable(declaration, data)
|
||||
@@ -181,16 +188,83 @@ private class FunctionParametersProcessor : IrElementVisitorVoid {
|
||||
private fun IrStatement.processFunctionParameter(inlinedBlock: IrInlinedFunctionBlock) {
|
||||
if (this !is IrVariable || !this.isTmpForInline) return
|
||||
|
||||
val varName = this.name.asString().substringAfterLast("_")
|
||||
val varNewName = when {
|
||||
this.origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER -> {
|
||||
val functionName = (inlinedBlock.inlineDeclaration as? IrDeclarationWithName)?.name
|
||||
functionName?.let { name -> "\$this$$name" } ?: AsmUtil.RECEIVER_PARAMETER_NAME
|
||||
}
|
||||
varName == SpecialNames.THIS.asStringStripSpecialMarkers() -> "this_"
|
||||
else -> varName
|
||||
}
|
||||
this.name = Name.identifier(varNewName + INLINE_FUN_VAR_SUFFIX)
|
||||
this.name = Name.identifier(calculateNewName(inlinedBlock) + INLINE_FUN_VAR_SUFFIX)
|
||||
this.origin = IrDeclarationOrigin.DEFINED
|
||||
}
|
||||
}
|
||||
|
||||
private class ScopeNumberVariableProcessor : IrElementVisitorVoid {
|
||||
private val inlinedStack = mutableListOf<Pair<IrInlinedFunctionBlock, Int>>()
|
||||
private var lastInlineScopeNumber = 0
|
||||
|
||||
private inline fun IrInlinedFunctionBlock.insertInStackAndProcess(block: IrInlinedFunctionBlock.() -> Unit) {
|
||||
lastInlineScopeNumber += 1
|
||||
inlinedStack += Pair(this, lastInlineScopeNumber)
|
||||
block()
|
||||
inlinedStack.removeLast()
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
val processor = ScopeNumberVariableProcessor()
|
||||
declaration.acceptChildrenVoid(processor)
|
||||
}
|
||||
|
||||
override fun visitBlock(expression: IrBlock) {
|
||||
if (expression !is IrInlinedFunctionBlock) {
|
||||
return super.visitBlock(expression)
|
||||
}
|
||||
|
||||
expression.insertInStackAndProcess {
|
||||
super.visitBlock(expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
if (inlinedStack.isEmpty()) {
|
||||
return super.visitVariable(declaration)
|
||||
}
|
||||
|
||||
val (inlinedBlock, scopeNumber) = inlinedStack.last()
|
||||
val newName = declaration.calculateNewName(inlinedBlock)
|
||||
declaration.name = Name.identifier(addInlineScopeInfo(newName, scopeNumber))
|
||||
super.visitVariable(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrVariable.calculateNewName(inlinedBlock: IrInlinedFunctionBlock): String {
|
||||
val varName = name.asString().substringAfterLast("_")
|
||||
return when {
|
||||
this.origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER ->
|
||||
inlinedBlock.getReceiverParameterName()
|
||||
varName == SpecialNames.THIS.asStringStripSpecialMarkers() ->
|
||||
AsmUtil.INLINE_DECLARATION_SITE_THIS
|
||||
else ->
|
||||
varName
|
||||
}
|
||||
}
|
||||
|
||||
private fun addInlineScopeInfo(name: String, scopeNumber: Int): String {
|
||||
val nameWithScopeNumber = name.addScopeInfo(scopeNumber)
|
||||
if (isFakeLocalVariableForInline(name)) {
|
||||
// During IR inlining we can't fetch call site line numbers because the line number mapping
|
||||
// has not been calculated yet. To keep the inline scope info format consistent, we will add
|
||||
// a mock call site line number instead, which will be replaced with the real one during the
|
||||
// expression codegen phase.
|
||||
val nameWithCallSiteLineNumber = nameWithScopeNumber.addScopeInfo(0)
|
||||
if (name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT)) {
|
||||
val surroundingScopeNumber = name.getInlineScopeInfo()?.surroundingScopeNumber ?: 0
|
||||
return nameWithCallSiteLineNumber.addScopeInfo(surroundingScopeNumber)
|
||||
}
|
||||
return nameWithCallSiteLineNumber
|
||||
}
|
||||
return nameWithScopeNumber
|
||||
}
|
||||
|
||||
private fun IrInlinedFunctionBlock.getReceiverParameterName(): String {
|
||||
val functionName = (inlineDeclaration as? IrDeclarationWithName)?.name
|
||||
return functionName?.let { "this$$it" } ?: AsmUtil.RECEIVER_PARAMETER_NAME
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user