[klib tool] Add option to print ir

Dumping the IR from a klib is useful for debugging klib compilations.

^KT-58877
This commit is contained in:
Johan Bay
2023-05-26 09:49:48 +02:00
committed by Space Team
parent b0f1746012
commit fafea27283
33 changed files with 753 additions and 24 deletions
@@ -196,14 +196,14 @@ fun main() {
// Klib contents tests
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeKlibContentsTest>(
suiteTestClassName = "NativeKLibContentsTestGenerated"
suiteTestClassName = "NativeKlibContentsTestGenerated"
) {
model("klibContents", pattern = "^([^_](.+)).kt$", recursive = true)
}
}
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeKlibContentsTest>(
suiteTestClassName = "FirNativeKLibContentsTestGenerated",
suiteTestClassName = "FirNativeKlibContentsTestGenerated",
annotations = listOf(
*frontendFir()
)
@@ -212,6 +212,25 @@ fun main() {
}
}
// Klib ir tests
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeKlibIrTest>(
suiteTestClassName = "NativeKlibIrTestGenerated",
) {
model("klibIr", pattern = "^([^_](.+)).kt$", recursive = true)
}
}
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeKlibIrTest>(
suiteTestClassName = "FirNativeKlibIrTestGenerated",
annotations = listOf(
*frontendFir()
)
) {
model("klibIr", pattern = "^([^_](.+)).kt$", recursive = true)
}
}
// LLDB integration tests.
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeBlackBoxTest>(
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.runner.TestRunChecks
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Binaries
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.CacheMode
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.KotlinNativeTargets
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.PipelineType
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Timeouts
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
import org.jetbrains.kotlin.test.Directives
@@ -36,7 +37,7 @@ import org.jetbrains.kotlin.compatibility.binary.TestModule as TModule
abstract class AbstractNativeKlibEvolutionTest : AbstractNativeSimpleTest() {
// Const evaluation tests muted for FIR because FIR does const propagation.
private fun isIgnoredTest(filePath: String): Boolean {
if (!this::class.java.simpleName.startsWith("Fir"))
if (testRunSettings.get<PipelineType>() != PipelineType.K2)
return false
val fileName = filePath.substringAfterLast('/')
@@ -0,0 +1,84 @@
/*
* Copyright 2010-2023 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.konan.blackboxtest
import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseId
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilerArgs
import org.jetbrains.kotlin.konan.blackboxtest.support.TestFile
import org.jetbrains.kotlin.konan.blackboxtest.support.TestKind
import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule
import org.jetbrains.kotlin.konan.blackboxtest.support.TestRunnerType
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.TestRunChecks
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.KotlinNativeClassLoader
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.PipelineType
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Timeouts
import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile
import org.jetbrains.kotlin.konan.blackboxtest.support.util.getIr
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEqualsToFile
import org.junit.jupiter.api.Tag
import java.io.File
@Tag("klib")
abstract class AbstractNativeKlibIrTest : AbstractNativeSimpleTest() {
protected fun runTest(@TestDataFile testPath: String) {
val testPathFull = getAbsoluteFile(testPath)
muteTestIfNecessary(testPathFull)
val testCase: TestCase = generateTestCaseWithSingleSource(
testPathFull,
listOf("-Xklib-relative-path-base=${testPathFull.parent}")
)
val testCompilationResult: TestCompilationResult.Success<out TestCompilationArtifact.KLIB> = compileToLibrary(testCase)
val testPathNoExtension = testPathFull.canonicalPath.substringBeforeLast(".")
val firSpecificExt =
if (testRunSettings.get<PipelineType>() == PipelineType.K2 && !firIdentical(testPathFull))
".fir"
else ""
val expectedContentsNoSig = File("$testPathNoExtension.ir$firSpecificExt.txt")
assertIrMatchesExpected(testCompilationResult, expectedContentsNoSig, printSignatures = false)
val expectedContentsWithSig = File("$testPathNoExtension.sig.ir$firSpecificExt.txt")
assertIrMatchesExpected(testCompilationResult, expectedContentsWithSig, printSignatures = true)
}
private fun assertIrMatchesExpected(
compilationResult: TestCompilationResult<out TestCompilationArtifact.KLIB>,
expectedContents: File,
printSignatures: Boolean
) {
val artifact = compilationResult.assertSuccess().resultingArtifact
val kotlinNativeClassLoader = testRunSettings.get<KotlinNativeClassLoader>()
val klibIr = artifact.getIr(kotlinNativeClassLoader.classLoader, printSignatures)
assertEqualsToFile(expectedContents, klibIr)
}
private fun generateTestCaseWithSingleSource(source: File, extraArgs: List<String>): TestCase {
val moduleName: String = source.name
val module = TestModule.Exclusive(moduleName, emptySet(), emptySet(), emptySet())
module.files += TestFile.createCommitted(source, module)
return TestCase(
id = TestCaseId.Named(moduleName),
kind = TestKind.STANDALONE,
modules = setOf(module),
freeCompilerArgs = TestCompilerArgs(extraArgs),
nominalPackageName = PackageName.EMPTY,
checks = TestRunChecks.Default(testRunSettings.get<Timeouts>().executionTimeout),
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT)
).apply {
initialize(null, null)
}
}
}
@@ -309,6 +309,9 @@ internal fun AbstractNativeSimpleTest.muteTestIfNecessary(testDataFileContents:
Assumptions.assumeFalse(mutedWhenValues.any { it == pipelineType.mutedOption.name })
}
internal fun AbstractNativeSimpleTest.firIdentical(testDataFile: File) =
InTextDirectivesUtils.isDirectiveDefined(FileUtil.loadFile(testDataFile), TestDirectives.FIR_IDENTICAL.name)
internal fun AbstractNativeSimpleTest.freeCompilerArgs(testDataFile: File) = freeCompilerArgs(FileUtil.loadFile(testDataFile))
internal fun AbstractNativeSimpleTest.freeCompilerArgs(testDataFileContents: String) =
directiveValues(testDataFileContents, TestDirectives.FREE_COMPILER_ARGS.name)
@@ -140,6 +140,10 @@ internal object TestDirectives : SimpleDirectivesContainer() {
Usage: // MUTED_WHEN: [K1, K2]
In native simple tests, specify the pipeline types to mute the test""".trimIndent(),
)
val FIR_IDENTICAL by directive(
description = "Test behavior should be identical for FIR testing"
)
}
internal enum class TestKind {
@@ -6,14 +6,27 @@
package org.jetbrains.kotlin.konan.blackboxtest.support.util
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact
import java.io.File
internal fun TestCompilationArtifact.KLIB.getContents(kotlinNativeClassLoader: ClassLoader): String {
private fun invokeKlibTool(kotlinNativeClassLoader: ClassLoader, klibFile: File, functionName: String, vararg args: Any): String {
val libraryClass = Class.forName("org.jetbrains.kotlin.cli.klib.Library", true, kotlinNativeClassLoader)
val entryPoint = libraryClass.declaredMethods.single { it.name == "contents" }
val entryPoint = libraryClass.declaredMethods.single { it.name == functionName }
val lib = libraryClass.getDeclaredConstructor(String::class.java, String::class.java, String::class.java)
.newInstance(klibFile.canonicalPath, null, "host")
val output = StringBuilder()
entryPoint.invoke(lib, output, false)
entryPoint.invoke(lib, output, *args)
return output.toString()
}
internal fun TestCompilationArtifact.KLIB.getContents(kotlinNativeClassLoader: ClassLoader): String {
return invokeKlibTool(kotlinNativeClassLoader, klibFile, "contents", false)
}
internal fun TestCompilationArtifact.KLIB.getIr(
kotlinNativeClassLoader: ClassLoader,
printSignatures: Boolean = false,
): String {
return invokeKlibTool(kotlinNativeClassLoader, klibFile, "ir", printSignatures)
}