[JVM] Implement new inlined variable naming format

^KT-65478 fixed
This commit is contained in:
Nikita Nazarov
2023-09-18 16:27:46 +02:00
committed by Alexander Udalov
parent 9ea775cbed
commit 407448d8e3
104 changed files with 88125 additions and 92 deletions
@@ -11,9 +11,11 @@ import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.CHECK_ASM_LIKE_INSTRUCTIONS
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.CURIOUS_ABOUT
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.FIR_DIFFERENCE
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.INLINE_SCOPES_DIFFERENCE
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.IR_DIFFERENCE
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.LOCAL_VARIABLE_TABLE
import org.jetbrains.kotlin.test.directives.AsmLikeInstructionListingDirectives.RENDER_ANNOTATIONS
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.USE_INLINE_SCOPES_NUMBERS
import org.jetbrains.kotlin.test.directives.model.Directive
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.BinaryArtifacts
@@ -38,6 +40,7 @@ class AsmLikeInstructionListingHandler(testServices: TestServices) : JvmBinaryAr
companion object {
const val DUMP_EXTENSION = "asm.txt"
const val IR_DUMP_EXTENSION = "asm.ir.txt"
const val INLINE_SCOPES_DUMP_EXTENSION = "asm.scopes.txt"
const val FIR_DUMP_EXTENSION = "asm.fir.txt"
const val LINE_SEPARATOR = "\n"
@@ -388,13 +391,20 @@ class AsmLikeInstructionListingHandler(testServices: TestServices) : JvmBinaryAr
val irDifference = IR_DIFFERENCE in testServices.moduleStructure.allDirectives
val firDifference = FIR_DIFFERENCE in testServices.moduleStructure.allDirectives
val inlineScopesDifference = INLINE_SCOPES_DIFFERENCE in testServices.moduleStructure.allDirectives
val firstModule = testServices.moduleStructure.modules.first()
val inlineScopesNumbersEnabled = firstModule.directives.contains(USE_INLINE_SCOPES_NUMBERS)
val extension = when {
firDifference && firstModule.frontendKind == FrontendKinds.FIR -> FIR_DUMP_EXTENSION
irDifference && firstModule.targetBackend?.isIR == true -> IR_DUMP_EXTENSION
else -> DUMP_EXTENSION
inlineScopesNumbersEnabled && inlineScopesDifference && firstModule.targetBackend?.isIR == true ->
INLINE_SCOPES_DUMP_EXTENSION
firDifference && firstModule.frontendKind == FrontendKinds.FIR ->
FIR_DUMP_EXTENSION
irDifference && firstModule.targetBackend?.isIR == true ->
IR_DUMP_EXTENSION
else ->
DUMP_EXTENSION
}
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
@@ -11,11 +11,13 @@ import org.jetbrains.kotlin.test.backend.codegenSuppressionChecker
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.CHECK_BYTECODE_TEXT
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.TREAT_AS_ONE_FILE
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.defaultDirectives
import org.jetbrains.kotlin.test.services.isKtFile
class BytecodeTextHandler(testServices: TestServices, private val shouldEnableExplicitly: Boolean = false) :
@@ -40,7 +42,14 @@ class BytecodeTextHandler(testServices: TestServices, private val shouldEnableEx
val file = files.first { !it.isAdditional }
val expected = readExpectedOccurrences(file.originalContent.split("\n"))
val actual = info.classFileFactory.createText(IGNORED_PREFIX)
checkGeneratedTextAgainstExpectedOccurrences(actual, expected, targetBackend, !isIgnored, assertions)
checkGeneratedTextAgainstExpectedOccurrences(
actual,
expected,
targetBackend,
!isIgnored,
assertions,
inlineScopesNumbersEnabled()
)
}
}
@@ -58,7 +67,14 @@ class BytecodeTextHandler(testServices: TestServices, private val shouldEnableEx
if (globalOccurrences.isNotEmpty()) {
val generatedText = info.classFileFactory.createText()
checkGeneratedTextAgainstExpectedOccurrences(generatedText, globalOccurrences, targetBackend, reportProblems, assertions)
checkGeneratedTextAgainstExpectedOccurrences(
generatedText,
globalOccurrences,
targetBackend,
reportProblems,
assertions,
inlineScopesNumbersEnabled()
)
}
val generatedByFile = info.classFileFactory.createTextForEachFile()
@@ -66,9 +82,20 @@ class BytecodeTextHandler(testServices: TestServices, private val shouldEnableEx
assertTextWasGenerated(expectedOutputFile, generatedByFile, assertions)
val generatedText = generatedByFile[expectedOutputFile]!!
val expectedOccurrences = expectedOccurrencesByOutputFile[expectedOutputFile]!!
checkGeneratedTextAgainstExpectedOccurrences(generatedText, expectedOccurrences, targetBackend, reportProblems, assertions)
checkGeneratedTextAgainstExpectedOccurrences(
generatedText,
expectedOccurrences,
targetBackend,
reportProblems,
assertions,
inlineScopesNumbersEnabled()
)
}
}
private fun inlineScopesNumbersEnabled(): Boolean {
return LanguageSettingsDirectives.USE_INLINE_SCOPES_NUMBERS in testServices.defaultDirectives
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.model.FrontendKind
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.defaultDirectives
import org.jetbrains.kotlin.test.services.sourceProviders.MainFunctionForBlackBoxTestsSourceProvider.Companion.BOX_MAIN_FILE_NAME
import org.jetbrains.kotlin.test.utils.*
import java.io.File
@@ -155,7 +156,7 @@ abstract class DebugRunner(testServices: TestServices) : JvmBoxRunner(testServic
}
eventSet.resume()
}
checkSteppingTestResult(frontend, backend, wholeFile, loggedItems)
checkSteppingTestResult(frontend, backend, wholeFile, loggedItems, testServices.defaultDirectives)
virtualMachine.resume()
}
@@ -17,6 +17,10 @@ object AsmLikeInstructionListingDirectives : SimpleDirectivesContainer() {
"If present then saves dump for IR backend in asm.ir.txt file"
)
val INLINE_SCOPES_DIFFERENCE by directive(
"If present and if inline scopes are enabled then saves dump for IR backend in asm.scopes.txt file"
)
val FIR_DIFFERENCE by directive(
"If present then saves dump for IR backend in asm.fir.txt file"
)
@@ -97,6 +97,12 @@ fun TestConfigurationBuilder.useIrInliner() {
}
}
fun TestConfigurationBuilder.useInlineScopesNumbers() {
defaultDirectives {
+LanguageSettingsDirectives.USE_INLINE_SCOPES_NUMBERS
}
}
fun TestConfigurationBuilder.applyDumpSmapDirective() {
forTestsMatching("compiler/testData/codegen/boxInline/smap/*") {
defaultDirectives {
@@ -0,0 +1,100 @@
/*
* Copyright 2010-2024 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.test.runners.codegen.inlineScopes
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.runners.codegen.*
/*
* All tests in this file are Fir Light Tree tests because they are meant to test inline scopes numbers
* in the JVM backend and their execution result shouldn't be affected by the parser.
*/
open class AbstractFirBlackBoxInlineCodegenWithBytecodeInlinerTestWithInlineScopes :
AbstractFirLightTreeBlackBoxInlineCodegenWithBytecodeInlinerTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
open class AbstractFirBlackBoxInlineCodegenWithIrInlinerTestWithInlineScopes : AbstractFirLightTreeBlackBoxInlineCodegenWithIrInlinerTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
// Adding this test will result in test failures.
// TODO: Decide what to do with this test
open class AbstractFirAsmLikeInstructionListingTestWithInlineScopes : AbstractFirLightTreeAsmLikeInstructionListingTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
open class AbstractFirBlackBoxCodegenTestWithInlineScopes : AbstractFirLightTreeBlackBoxCodegenTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
// Adding this test will result in test failures.
// TODO: Add or remove when the fate of the IR inliner is decided.
open class AbstractFirBlackBoxCodegenWithIrInlinerTestWithInlineScopes : AbstractFirLightTreeBlackBoxCodegenTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
builder.useIrInliner()
}
}
open class AbstractFirBytecodeTextTestWithInlineScopes : AbstractFirLightTreeBytecodeTextTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
open class AbstractFirLocalVariableBytecodeInlinerTestWithInlineScopes : AbstractFirLightTreeLocalVariableTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
open class AbstractFirLocalVariableIrInlinerTestWithInlineScopes : AbstractFirLightTreeLocalVariableTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
builder.useIrInliner()
}
}
open class AbstractFirSerializeCompileKotlinAgainstInlineKotlinTestWithInlineScopes :
AbstractFirLightTreeSerializeCompileKotlinAgainstInlineKotlinTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
open class AbstractFirSteppingWithBytecodeInlinerTestWithInlineScopes : AbstractFirLightTreeSteppingTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
}
}
open class AbstractFirSteppingWithIrInlinerTestWithInlineScopes : AbstractFirLightTreeSteppingTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.useInlineScopesNumbers()
builder.useIrInliner()
}
}
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.DISABLE_CALL_ASSERTIONS
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.DISABLE_PARAM_ASSERTIONS
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.EMIT_JVM_TYPE_ANNOTATIONS
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.USE_INLINE_SCOPES_NUMBERS
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.ENABLE_JVM_IR_INLINER
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.ENABLE_JVM_PREVIEW
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.JDK_RELEASE
@@ -180,6 +181,7 @@ open class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentC
register(OLD_INNER_CLASSES_LOGIC, JVMConfigurationKeys.OLD_INNER_CLASSES_LOGIC)
register(LINK_VIA_SIGNATURES_K1, JVMConfigurationKeys.LINK_VIA_SIGNATURES)
register(ENABLE_JVM_IR_INLINER, JVMConfigurationKeys.ENABLE_IR_INLINER)
register(USE_INLINE_SCOPES_NUMBERS, JVMConfigurationKeys.USE_INLINE_SCOPES_NUMBERS)
}
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
@@ -6,6 +6,9 @@
package org.jetbrains.kotlin.test.utils
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.model.Directive
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.model.FrontendKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEqualsToFile
@@ -56,16 +59,46 @@ private fun String.normalizeIndyLambdas(): String =
private const val EXPECTATIONS_MARKER = "// EXPECTATIONS"
private const val FORCE_STEP_INTO_MARKER = "// FORCE_STEP_INTO"
private const val DIRECTIVE_MARKER = "+"
data class BackendWithDirectives(val backend: TargetBackend) {
companion object {
private val directivesToConsider = mutableSetOf(LanguageSettingsDirectives.USE_INLINE_SCOPES_NUMBERS)
}
private val directives = mutableSetOf<Directive>()
fun addDirectiveIfConsidered(directive: Directive) {
if (directive in directivesToConsider) {
directives += directive
}
}
fun contains(registeredDirectives: RegisteredDirectives, directivesInTestFile: Set<Directive>): Boolean {
if (directivesInTestFile.isEmpty()) return true
return registeredDirectives.filter { it in directivesToConsider && it in directivesInTestFile }.toSet() == directives
}
}
fun checkSteppingTestResult(
frontendKind: FrontendKind<*>,
targetBackend: TargetBackend,
wholeFile: File,
loggedItems: List<SteppingTestLoggedData>
loggedItems: List<SteppingTestLoggedData>,
directives: RegisteredDirectives
) {
val actual = mutableListOf<String>()
val lines = wholeFile.readLines()
val forceStepInto = lines.any { it.startsWith(FORCE_STEP_INTO_MARKER) }
val directivesInTestFile = mutableSetOf<Directive>()
var forceStepInto = false
for (line in lines) {
if (line.contains(DIRECTIVE_MARKER)) {
directivesInTestFile.addAll(line.getDeclaredDirectives())
}
if (line.startsWith(FORCE_STEP_INTO_MARKER)) {
forceStepInto = true
}
}
val actualLineNumbers = compressSequencesWithoutLineNumber(loggedItems)
.filter {
@@ -86,8 +119,8 @@ fun checkSteppingTestResult(
if (line.startsWith(FORCE_STEP_INTO_MARKER)) break
}
var currentBackends = setOf(TargetBackend.ANY)
var currentFrontends = setOf(frontendKind)
var currentBackends = listOf(BackendWithDirectives(TargetBackend.ANY))
var currentFrontends = listOf(frontendKind)
for (line in lineIterator) {
if (line.isEmpty()) {
actual.add(line)
@@ -95,20 +128,41 @@ fun checkSteppingTestResult(
}
if (line.startsWith(EXPECTATIONS_MARKER)) {
actual.add(line)
val backendsAndFrontends = line.removePrefix(EXPECTATIONS_MARKER).splitToSequence(Regex("\\s+")).filter { it.isNotEmpty() }
currentBackends = backendsAndFrontends
.mapNotNullTo(mutableSetOf()) { valueOfOrNull<TargetBackend>(it) }
.takeIf { it.isNotEmpty() }
?: setOf(TargetBackend.ANY)
currentFrontends = backendsAndFrontends
.mapNotNullTo(mutableSetOf(), FrontendKinds::fromString)
.takeIf { it.isNotEmpty() }
?: setOf(frontendKind)
val options = line.removePrefix(EXPECTATIONS_MARKER).splitToSequence(Regex("\\s+")).filter { it.isNotEmpty() }
val backends = mutableListOf<BackendWithDirectives>()
val frontends = mutableListOf<FrontendKind<*>>()
var currentBackendWithDirectives: BackendWithDirectives? = null
for (option in options) {
val backend = valueOfOrNull<TargetBackend>(option)
if (backend != null) {
val backendWithDirectives = BackendWithDirectives(backend)
currentBackendWithDirectives = backendWithDirectives
backends += backendWithDirectives
continue
}
val frontend = FrontendKinds.fromString(option)
if (frontend != null) {
frontends += frontend
continue
}
val directive = LanguageSettingsDirectives[option.substringAfter(DIRECTIVE_MARKER)]
if (directive != null && currentBackendWithDirectives != null) {
currentBackendWithDirectives.addDirectiveIfConsidered(directive)
}
}
currentBackends = backends.takeIf { it.isNotEmpty() } ?: listOf(BackendWithDirectives(TargetBackend.ANY))
currentFrontends = frontends.takeIf { it.isNotEmpty() } ?: listOf(frontendKind)
continue
}
if ((currentBackends.contains(TargetBackend.ANY) || currentBackends.contains(targetBackend)) &&
currentFrontends.contains(frontendKind)
) {
val containsBackend =
currentBackends.any {
it.backend == TargetBackend.ANY || (it.backend == targetBackend && it.contains(directives, directivesInTestFile))
}
if (containsBackend && currentFrontends.contains(frontendKind)) {
if (actualLineNumbersIterator.hasNext()) {
actual.add(actualLineNumbersIterator.next())
}
@@ -125,6 +179,10 @@ fun checkSteppingTestResult(
assertEqualsToFile(wholeFile, actual.joinToString("\n"))
}
private fun String.getDeclaredDirectives(): List<Directive> {
return split(Regex("\\s+")).mapNotNull { LanguageSettingsDirectives[it.substringAfter(DIRECTIVE_MARKER)] }
}
/**
* Compresses sequences of the same location without line number in the log:
* specifically removes locations without linenumber, that would otherwise