[IR][JS] Partial linkage: Support KLIB ABI compat tests w/ and w/o IC

This commit is contained in:
Dmitriy Dolovov
2022-10-14 15:37:10 +02:00
committed by Space Team
parent afcf78ac94
commit 6f8c2a36f9
4 changed files with 212 additions and 25 deletions
@@ -43,7 +43,12 @@ fun main(args: Array<String>) {
}
testGroup("js/js.tests/tests-gen", "compiler/testData") {
testClass<AbstractJsKLibABITestCase> {
testClass<AbstractJsKLibABIWithICTestCase> {
model("klibABI/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR, recursive = false, )
}
}
testGroup("js/js.tests/tests-gen", "compiler/testData") {
testClass<AbstractJsKLibABINoICTestCase> {
model("klibABI/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR, recursive = false, )
}
}
@@ -14,8 +14,11 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
import org.jetbrains.kotlin.ir.backend.js.ic.CacheUpdater
import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformerTmp
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
@@ -28,7 +31,17 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind
import java.io.File
abstract class AbstractJsKLibABIWithICTestCase : AbstractJsKLibABITestCase() {
override val useIncrementalCompiler get() = true
}
abstract class AbstractJsKLibABINoICTestCase : AbstractJsKLibABITestCase() {
override val useIncrementalCompiler get() = false
}
abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() {
abstract val useIncrementalCompiler: Boolean
override fun stdlibFile(): File = File("libraries/stdlib/js-ir/build/classes/kotlin/js/main").absoluteFile
override fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection<File>, klibFile: File) {
@@ -50,37 +63,22 @@ abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() {
}
override fun buildBinaryAndRun(mainModuleKlibFile: File, libraries: Collection<File>) {
val project = environment.project
val configuration = environment.configuration
val configuration = environment.configuration.copy()
configuration.put(JSConfigurationKeys.PARTIAL_LINKAGE, true)
configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
configuration.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true)
configuration.put(CommonConfigurationKeys.MODULE_NAME, MAIN_MODULE_NAME)
val kLib = MainModule.Klib(mainModuleKlibFile.path)
val moduleStructure = ModulesStructure(project, kLib, configuration, libraries.map { it.path }, emptyList())
val ir = compile(
moduleStructure,
PhaseConfig(jsPhases),
IrFactoryImplForJsIC(WholeWorldStageController()),
exportedDeclarations = setOf(FqName("box")),
granularity = JsGenerationGranularity.PER_MODULE,
icCompatibleIr2Js = true
)
val transformer = IrModuleToJsTransformerTmp(ir.context, emptyList())
val compiledResult = transformer.generateModule(ir.allModules, setOf(TranslationMode.FULL_DCE_MINIMIZED_NAMES), false)
val dceOutput = compiledResult.outputs[TranslationMode.FULL_DCE_MINIMIZED_NAMES] ?: error("No DCE output")
val compilationOutputs = if (useIncrementalCompiler)
buildBinaryWithIC(configuration, mainModuleKlibFile, libraries)
else
buildBinaryNoIC(configuration, mainModuleKlibFile, libraries)
val binariesDir = File(buildDir, BIN_DIR_NAME).also { it.mkdirs() }
val binaries = ArrayList<File>(libraries.size)
for ((name, code) in dceOutput.dependencies) {
for ((name, code) in compilationOutputs.dependencies) {
val depBinary = binariesDir.binJsFile(name)
depBinary.parentFile?.let { if (!it.exists()) it.mkdirs() }
depBinary.writeText(code.jsCode)
@@ -88,12 +86,73 @@ abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() {
}
val mainBinary = binariesDir.binJsFile(MAIN_MODULE_NAME)
mainBinary.writeText(dceOutput.jsCode)
mainBinary.writeText(compilationOutputs.jsCode)
binaries.add(mainBinary)
executeAndCheckBinaries(MAIN_MODULE_NAME, binaries)
}
private fun buildBinaryWithIC(
configuration: CompilerConfiguration,
mainModuleKlibFile: File,
libraries: Collection<File>
): CompilationOutputs {
fun cacheDir(library: File): File = buildDir.resolve("libs-cache").resolve(library.name).apply { mkdirs() }
val cacheUpdater = CacheUpdater(
mainModule = mainModuleKlibFile.absolutePath,
allModules = libraries.map { it.absolutePath },
icCachePaths = libraries.map { cacheDir(it).absolutePath },
compilerConfiguration = configuration,
irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) },
mainArguments = null,
compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC(mainModule, cfg, setOf(BOX_FUN_FQN)) }
)
val icCaches = cacheUpdater.actualizeCaches()
val mainModuleName = icCaches.last().moduleExternalName
val jsExecutableProducer = JsExecutableProducer(
mainModuleName = mainModuleName,
moduleKind = configuration[JSConfigurationKeys.MODULE_KIND]!!,
sourceMapsInfo = SourceMapsInfo.from(configuration),
caches = icCaches,
relativeRequirePath = true
)
return jsExecutableProducer.buildExecutable(multiModule = true, outJsProgram = true) {}
}
private fun buildBinaryNoIC(
configuration: CompilerConfiguration,
mainModuleKlibFile: File,
libraries: Collection<File>
): CompilationOutputs {
val klib = MainModule.Klib(mainModuleKlibFile.path)
val moduleStructure = ModulesStructure(environment.project, klib, configuration, libraries.map { it.path }, emptyList())
val ir = compile(
moduleStructure,
PhaseConfig(jsPhases),
IrFactoryImplForJsIC(WholeWorldStageController()),
exportedDeclarations = setOf(BOX_FUN_FQN),
granularity = JsGenerationGranularity.PER_MODULE,
icCompatibleIr2Js = true
)
val transformer = IrModuleToJsTransformerTmp(
backendContext = ir.context,
mainArguments = emptyList()
)
val compiledResult = transformer.generateModule(
modules = ir.allModules,
modes = setOf(TranslationMode.FULL_DCE_MINIMIZED_NAMES),
relativeRequirePath = false
)
return compiledResult.outputs[TranslationMode.FULL_DCE_MINIMIZED_NAMES] ?: error("No DCE output")
}
private fun KotlinCoreEnvironment.createPsiFiles(sourceDir: File): List<KtFile> {
val psiManager = PsiManager.getInstance(project)
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL) as CoreLocalFileSystem
@@ -112,10 +171,11 @@ abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() {
val checker = V8IrJsTestChecker
val filePaths = dependencies.map { it.canonicalPath }
checker.check(filePaths, mainModuleName, null, "box", "OK", withModuleSystem = false)
checker.check(filePaths, mainModuleName, null, BOX_FUN_FQN.asString(), "OK", withModuleSystem = false)
}
companion object {
private const val BIN_DIR_NAME = "_bins_js"
private val BOX_FUN_FQN = FqName("box")
}
}
@@ -21,7 +21,7 @@ import java.util.regex.Pattern;
@TestMetadata("compiler/testData/klibABI")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class JsKLibABITestCaseGenerated extends AbstractJsKLibABITestCase {
public class JsKLibABINoICTestCaseGenerated extends AbstractJsKLibABINoICTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
@@ -0,0 +1,122 @@
/*
* Copyright 2010-2022 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.js.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateJsTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/klibABI")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class JsKLibABIWithICTestCaseGenerated extends AbstractJsKLibABIWithICTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInKlibABI() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/klibABI"), Pattern.compile("^([^_](.+))$"), null, TargetBackend.JS_IR, false);
}
@TestMetadata("removeAbstractFunctionFromAbstractClass")
public void testRemoveAbstractFunctionFromAbstractClass() throws Exception {
runTest("compiler/testData/klibABI/removeAbstractFunctionFromAbstractClass/");
}
@TestMetadata("removeAbstractFunctionFromInterface")
public void testRemoveAbstractFunctionFromInterface() throws Exception {
runTest("compiler/testData/klibABI/removeAbstractFunctionFromInterface/");
}
@TestMetadata("removeAbstractPropertyFromAbstractClass")
public void testRemoveAbstractPropertyFromAbstractClass() throws Exception {
runTest("compiler/testData/klibABI/removeAbstractPropertyFromAbstractClass/");
}
@TestMetadata("removeAbstractPropertyFromInterface")
public void testRemoveAbstractPropertyFromInterface() throws Exception {
runTest("compiler/testData/klibABI/removeAbstractPropertyFromInterface/");
}
@TestMetadata("removeClassAsConstructorCall")
public void testRemoveClassAsConstructorCall() throws Exception {
runTest("compiler/testData/klibABI/removeClassAsConstructorCall/");
}
@TestMetadata("removeClassAsParameterType")
public void testRemoveClassAsParameterType() throws Exception {
runTest("compiler/testData/klibABI/removeClassAsParameterType/");
}
@TestMetadata("removeClassAsReturnType")
public void testRemoveClassAsReturnType() throws Exception {
runTest("compiler/testData/klibABI/removeClassAsReturnType/");
}
@TestMetadata("removeClassAsSuperTypeArgument")
public void testRemoveClassAsSuperTypeArgument() throws Exception {
runTest("compiler/testData/klibABI/removeClassAsSuperTypeArgument/");
}
@TestMetadata("removeClassAsTypeArgument")
public void testRemoveClassAsTypeArgument() throws Exception {
runTest("compiler/testData/klibABI/removeClassAsTypeArgument/");
}
@TestMetadata("removeClassAsVariableType")
public void testRemoveClassAsVariableType() throws Exception {
runTest("compiler/testData/klibABI/removeClassAsVariableType/");
}
@TestMetadata("removeFunction")
public void testRemoveFunction() throws Exception {
runTest("compiler/testData/klibABI/removeFunction/");
}
@TestMetadata("removeInlinedClass")
public void testRemoveInlinedClass() throws Exception {
runTest("compiler/testData/klibABI/removeInlinedClass/");
}
@TestMetadata("removeInlinedFunction")
public void testRemoveInlinedFunction() throws Exception {
runTest("compiler/testData/klibABI/removeInlinedFunction/");
}
@TestMetadata("removeInlinedProperty")
public void testRemoveInlinedProperty() throws Exception {
runTest("compiler/testData/klibABI/removeInlinedProperty/");
}
@TestMetadata("removeOpenFunction")
public void testRemoveOpenFunction() throws Exception {
runTest("compiler/testData/klibABI/removeOpenFunction/");
}
@TestMetadata("removeOpenProperty")
public void testRemoveOpenProperty() throws Exception {
runTest("compiler/testData/klibABI/removeOpenProperty/");
}
@TestMetadata("removeProperty")
public void testRemoveProperty() throws Exception {
runTest("compiler/testData/klibABI/removeProperty/");
}
@TestMetadata("typeAliasRHSTypeChange")
public void testTypeAliasRHSTypeChange() throws Exception {
runTest("compiler/testData/klibABI/typeAliasRHSTypeChange/");
}
}