[K/N] Run irText tests for K1/Native
^KT-58240
This commit is contained in:
committed by
Space Team
parent
40c9f831e2
commit
3aa6c9e74d
+2923
File diff suppressed because it is too large
Load Diff
@@ -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).
|
||||
|
||||
+155
@@ -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
|
||||
}
|
||||
}
|
||||
+16
-2
@@ -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) }
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
+27
@@ -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
|
||||
}
|
||||
+40
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user