[K/N] Run irText tests for K1/Native

^KT-58240
This commit is contained in:
Vladimir Sukharev
2023-08-09 22:21:59 +02:00
committed by Space Team
parent 40c9f831e2
commit 3aa6c9e74d
69 changed files with 3376 additions and 73 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.group.UsePartialLinkage
import org.jetbrains.kotlin.konan.diagnostics.AbstractDiagnosticsNativeTest
import org.jetbrains.kotlin.konan.diagnostics.AbstractFirLightTreeNativeDiagnosticsTest
import org.jetbrains.kotlin.konan.diagnostics.AbstractFirPsiNativeDiagnosticsTest
import org.jetbrains.kotlin.konan.irtext.AbstractClassicNativeIrTextTest
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.utils.CUSTOM_TEST_DATA_EXTENSION_PATTERN
import org.junit.jupiter.api.Tag
@@ -76,6 +77,9 @@ fun main() {
model("codegen/box", targetBackend = TargetBackend.NATIVE)
model("codegen/boxInline", targetBackend = TargetBackend.NATIVE)
}
testClass<AbstractClassicNativeIrTextTest> {
model("ir/irText")
}
}
// Samples (how to utilize the abilities of new test infrastructure).
@@ -0,0 +1,155 @@
/*
* 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
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
import org.jetbrains.kotlin.ir.linkage.partial.partialLinkageConfig
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.blackboxtest.support.CastCompatibleKotlinNativeClassLoader
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.model.BackendKinds
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import kotlin.reflect.KClass
class ClassicFrontend2NativeIrConverter(
testServices: TestServices,
) : Frontend2BackendConverter<ClassicFrontendOutputArtifact, IrBackendInput>(
testServices,
FrontendKinds.ClassicFrontend,
BackendKinds.IrBackend
) {
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::LibraryProvider))
override fun transform(module: TestModule, inputArtifact: ClassicFrontendOutputArtifact): IrBackendInput {
return when (module.targetBackend) {
TargetBackend.NATIVE -> transformToNativeIr(module, inputArtifact)
else -> testServices.assertions.fail { "Target backend ${module.targetBackend} is not supported for transformation into IR" }
}
}
/**
* Mostly mimics [org.jetbrains.kotlin.backend.konan.psiToIr], since direct call is impossible due to:
* - prohibited import of module `:kotlin-native:backend.native` here to `:native:native.tests`
* - invocation via reflection is complicated due to moving [com.intellij.openapi.project.Project] to another subpackage during compiler
* JAR embedding.
*
* It's unlikely that [org.jetbrains.kotlin.backend.konan.psiToIr] would be ever significantly changed before reaching its end-of-life,
* so it's plausible to have a reduced copy here in the test pipeline.
*/
private fun transformToNativeIr(module: TestModule, inputArtifact: ClassicFrontendOutputArtifact): IrBackendInput {
val (psiFiles, analysisResult, project, _) = inputArtifact
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val sourceFiles: List<KtFile> = psiFiles.values.toList()
val translator = Psi2IrTranslator(
configuration.languageVersionSettings,
Psi2IrConfiguration(ignoreErrors = false, configuration.partialLinkageConfig.isEnabled),
configuration.irMessageLogger::checkNoUnboundSymbols
)
val konanManglerDescClass = kotlinNativeClass("org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc")
val manglerDesc = konanManglerDescClass.objectInstance as KotlinMangler.DescriptorMangler
val konanIdSignaturerClass = kotlinNativeClass("org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer")
val konanIdSignaturerConstructor = konanIdSignaturerClass.constructors.single()
val konanIdSignaturerClassInstance = konanIdSignaturerConstructor.call(manglerDesc) as IdSignatureComposer
val symbolTable = SymbolTable(konanIdSignaturerClassInstance, IrFactoryImpl)
val generatorContext = translator.createGeneratorContext(
analysisResult.moduleDescriptor,
analysisResult.bindingContext,
symbolTable
)
val konanStubGeneratorExtensionsClass = kotlinNativeClass("org.jetbrains.kotlin.backend.konan.KonanStubGeneratorExtensions")
val stubGenerator = DeclarationStubGeneratorImpl(
analysisResult.moduleDescriptor, symbolTable,
generatorContext.irBuiltIns,
DescriptorByIdSignatureFinderImpl(analysisResult.moduleDescriptor, manglerDesc),
konanStubGeneratorExtensionsClass.objectInstance as StubGeneratorExtensions
).apply {
unboundSymbolGeneration = true
}
val irDeserializer = object : IrDeserializer {
override fun getDeclaration(symbol: IrSymbol) = stubGenerator.getDeclaration(symbol)
override fun resolveBySignatureInModule(
signature: IdSignature,
kind: IrDeserializer.TopLevelSymbolKind,
moduleName: Name
): IrSymbol {
error("Should not be called")
}
override fun postProcess(inOrAfterLinkageStep: Boolean) = Unit
}
val pluginExtensions = IrGenerationExtension.getInstances(project)
val moduleFragment = translator.generateModuleFragment(
generatorContext,
sourceFiles,
irProviders = listOf(irDeserializer),
linkerExtensions = pluginExtensions,
).toKonanModule()
val pluginContext = IrPluginContextImpl(
generatorContext.moduleDescriptor,
generatorContext.bindingContext,
generatorContext.languageVersionSettings,
generatorContext.symbolTable,
generatorContext.typeTranslator,
generatorContext.irBuiltIns,
linker = irDeserializer,
diagnosticReporter = configuration.irMessageLogger
)
val konanManglerIrClassKotlin = kotlinNativeClass("org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr")
val konanIrMangler = konanManglerIrClassKotlin.objectInstance as KotlinMangler.IrMangler
return IrBackendInput.NativeBackendInput(
moduleFragment,
dependentIrModuleFragments = emptyList(),
pluginContext,
diagnosticReporter = DiagnosticReporterFactory.createReporter(),
descriptorMangler = (pluginContext.symbolTable as SymbolTable).signaturer.mangler,
irMangler = konanIrMangler,
firMangler = null,
)
}
private fun IrModuleFragment.toKonanModule(): IrModuleFragment {
val konanIrModuleFragmentImplClass = kotlinNativeClass("org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleFragmentImpl")
return konanIrModuleFragmentImplClass.constructors.single().call(descriptor, irBuiltins, files) as IrModuleFragment
}
private fun kotlinNativeClass(name: String): KClass<out Any> {
// KT-61248: TODO Replace reflection for direct import, when classes would be extracted out of `backend.native` module
return Class.forName(
name,
true,
CastCompatibleKotlinNativeClassLoader.kotlinNativeClassLoader.classLoader
).kotlin
}
}
@@ -70,6 +70,10 @@ class NativeSimpleTestSupport : BeforeEachCallback {
}
}
internal object CastCompatibleKotlinNativeClassLoader {
val kotlinNativeClassLoader = NativeTestSupport.computeNativeClassLoader(this::class.java.classLoader)
}
private object NativeTestSupport {
private val NAMESPACE = ExtensionContext.Namespace.create(NativeTestSupport::class.java.simpleName)
@@ -93,14 +97,24 @@ private object NativeTestSupport {
private fun computeNativeHome(): KotlinNativeHome = KotlinNativeHome(File(ProcessLevelProperty.KOTLIN_NATIVE_HOME.readValue()))
private fun computeNativeClassLoader(): KotlinNativeClassLoader = KotlinNativeClassLoader(
/**
* - For Codegen native tests, no parent classloader should be provided,
* since compiler `class K2Native: CLICompiler` is invoked via reflection with kotlinNativeClassLoader,
* so both classes K2Native and CLICompiler need to be loaded with same nativeclassloader.
* This way, `K2Native.doExecute()` method would define abstract method `CLICompiler.doExecute()`.
* With parent classloader, these two classes would be loaded by different classloaders and AbstractMethodError is thrown
* - For irText tests, classloaded mangler instance is passed to generate mangles to IR dumps files.
* For this, a cast of mangler object(within K/N classloader) to mangler interface(within app classloader) is needed,
* which is possible when app classloader is provided as parent.
*/
fun computeNativeClassLoader(parent: ClassLoader? = null): KotlinNativeClassLoader = KotlinNativeClassLoader(
lazy {
val nativeClassPath = ProcessLevelProperty.COMPILER_CLASSPATH.readValue()
.split(':', ';')
.map { File(it).toURI().toURL() }
.toTypedArray()
URLClassLoader(nativeClassPath, /* no parent class loader */ null).apply { setDefaultAssertionStatus(true) }
URLClassLoader(nativeClassPath, parent).apply { setDefaultAssertionStatus(true) }
}
)
@@ -0,0 +1,27 @@
/*
* 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.irtext
import org.jetbrains.kotlin.konan.ClassicFrontend2NativeIrConverter
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.model.FrontendFacade
import org.jetbrains.kotlin.test.model.FrontendKind
import org.jetbrains.kotlin.test.model.FrontendKinds
open class AbstractClassicNativeIrTextTest: AbstractNativeIrTextTestBase<ClassicFrontendOutputArtifact>() {
override val frontend: FrontendKind<*>
get() = FrontendKinds.ClassicFrontend
override val frontendFacade: Constructor<FrontendFacade<ClassicFrontendOutputArtifact>>
get() = ::ClassicFrontendFacade
override val converter: Constructor<Frontend2BackendConverter<ClassicFrontendOutputArtifact, IrBackendInput>>
get() = ::ClassicFrontend2NativeIrConverter
}
@@ -0,0 +1,40 @@
/*
* 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.irtext
import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
import org.jetbrains.kotlin.test.model.ResultingArtifact
import org.jetbrains.kotlin.test.runners.ir.AbstractIrTextTest
import org.jetbrains.kotlin.test.services.LibraryProvider
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.NativeEnvironmentConfigurator
abstract class AbstractNativeIrTextTestBase<FrontendOutput : ResultingArtifact.FrontendOutput<FrontendOutput>> :
AbstractIrTextTest<FrontendOutput>(NativePlatforms.unspecifiedNativePlatform, TargetBackend.NATIVE) {
final override fun TestConfigurationBuilder.applyConfigurators() {
useConfigurators(
::CommonEnvironmentConfigurator,
::NativeEnvironmentConfigurator,
)
useAdditionalService(::LibraryProvider)
}
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
// Kotlin/Native does not have "minimal" stdlib(like other backends do), so full stdlib is needed to resolve
// `Any`, `String`, `println`, etc.
+ConfigurationDirectives.WITH_STDLIB
}
}
}
}