[JS IC] Support //RECOMPILE directive in js box tests

- change test runner to production mode when sources are being compiled
 into klib and then klib is being translated into js, not directly from
 kt to js
 - fix IC cache format
 - support IC tests
This commit is contained in:
Roman Artemev
2021-09-09 15:44:14 +03:00
committed by teamcityserver
parent 6b2fee7143
commit a2e4ebd820
8 changed files with 225 additions and 118 deletions
@@ -38,9 +38,7 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.ic.actualizeCacheForModule
import org.jetbrains.kotlin.ir.backend.js.ic.buildCache
import org.jetbrains.kotlin.ir.backend.js.ic.checkCaches
import org.jetbrains.kotlin.ir.backend.js.ic.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
@@ -76,6 +74,10 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
@Suppress("UNUSED_PARAMETER")
private fun usePerFileInvalidator(configuration: CompilerConfiguration): Boolean = false
private fun IcCacheInfo.toICCacheMap(): Map<String, ICCache> {
return data.map { it.key to ICCache(PersistentCacheProvider.EMPTY, PersistentCacheConsumer.EMPTY, it.value) }.toMap()
}
override fun doExecute(
arguments: K2JSCompilerArguments,
configuration: CompilerConfiguration,
@@ -234,7 +236,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
// Run analysis if main module is sources
lateinit var sourceModule: ModulesStructure
if (arguments.includes == null) {
val includes = arguments.includes
if (includes == null) {
do {
sourceModule = prepareAnalyzedSourceModule(
projectJs,
@@ -245,7 +248,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
AnalyzerWithCompilerReport(config.configuration),
icUseGlobalSignatures = icCaches.isNotEmpty(),
icUseStdlibCache = icCaches.isNotEmpty(),
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = arguments.includes).data else emptyMap()
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).toICCacheMap() else emptyMap()
)
val result = sourceModule.jsFrontEndResult.jsAnalysisResult
if (result is JsAnalysisResult.RetryWithAdditionalRoots) {
@@ -276,8 +279,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
val includes = arguments.includes
val module = if (includes != null) {
if (sourcesFiles.isNotEmpty()) {
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
@@ -294,7 +295,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
friendLibraries,
icUseGlobalSignatures = icCaches.isNotEmpty(),
icUseStdlibCache = icCaches.isNotEmpty(),
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).data else emptyMap()
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).toICCacheMap() else emptyMap()
)
} else {
sourceModule
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.backend.js.ic
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.backend.js.MainModule
import org.jetbrains.kotlin.ir.backend.js.toByteArray
@@ -20,6 +19,10 @@ import kotlin.random.nextULong
// TODO: Proper version of the compiler (should take changes to lowerings into account)
private val compilerVersion = Random.nextULong()
private fun IcCacheInfo.toICCacheMap(): Map<String, ICCache> {
return data.map { it.key to ICCache(PersistentCacheProvider.EMPTY, PersistentCacheConsumer.EMPTY, it.value) }.toMap()
}
// TODO more parameters for lowerings
// Returns true if caches were built. False if caches were up-to-date.
fun buildCache(
@@ -50,9 +53,9 @@ fun buildCache(
File(icDir, "info").delete()
icDir.mkdirs()
val icData = prepareSingleLibraryIcCache(project, configuration, mainModule.libPath, dependencies, friendDependencies, exportedDeclarations, icCache.data)
val icData = prepareSingleLibraryIcCache(project, configuration, mainModule.libPath, dependencies, friendDependencies, exportedDeclarations, icCache.toICCacheMap())
icData.writeTo(File(cachePath))
icData.serializedIcData.writeTo(File(cachePath))
CacheInfo(cachePath, mainModule.libPath, md5).save()
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.backend.js.ic
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
import org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.backend.js.*
@@ -34,8 +33,8 @@ fun prepareSingleLibraryIcCache(
dependencies: Collection<String>,
friendDependencies: Collection<String> = emptyList(),
exportedDeclarations: Set<FqName> = emptySet(),
icCache: Map<String, SerializedIcData> = emptyMap(),
): SerializedIcData {
icCache: Map<String, ICCache> = emptyMap(),
): ICCache {
val irFactory = PersistentIrFactory()
val controller = WholeWorldStageController()
irFactory.stageController = controller
@@ -67,13 +66,17 @@ fun prepareSingleLibraryIcCache(
lowerPreservingIcData(moduleFragment, context, controller)
return IcSerializer(
context.irBuiltIns,
context.mapping,
irFactory,
deserializer,
moduleFragment
).serializeDeclarations(irFactory.allDeclarations)
return ICCache(
PersistentCacheProvider.EMPTY,
PersistentCacheConsumer.EMPTY,
IcSerializer(
context.irBuiltIns,
context.mapping,
irFactory,
deserializer,
moduleFragment
).serializeDeclarations(irFactory.allDeclarations)
)
}
private fun KotlinResolvedLibrary.allDependencies(): List<KotlinResolvedLibrary> {
@@ -265,7 +265,8 @@ private fun createCacheConsumer(path: String): PersistentCacheConsumer {
private fun loadCacheInfo(cachePaths: Collection<String>): MutableMap<ModulePath, String> {
val caches = cachePaths.map { CacheInfo.load(it) ?: error("Cannot load IC cache from $it") }
return caches.associate { it.libPath.toCanonicalPath() to it.path } as MutableMap<ModulePath, String>
val result = mutableMapOf<ModulePath, String>()
return caches.associateTo(result) { it.libPath.toCanonicalPath() to it.path }
}
private fun loadLibraries(configuration: CompilerConfiguration, dependencies: Collection<String>): Map<ModulePath, KotlinLibrary> {
@@ -298,7 +299,7 @@ fun actualizeCacheForModule(
val libraries: Map<ModulePath, KotlinLibrary> = loadLibraries(compilerConfiguration, dependencies)
val persistentCacheProviders = icCacheMap.map { (lib, cache) ->
libraries[lib.toCanonicalPath()]!!.let { klib -> klib to createCacheProvider(cache) }
libraries[lib.toCanonicalPath()]!! to createCacheProvider(cache)
}.toMap()
val nameToKotlinLibrary: Map<ModuleName, KotlinLibrary> = libraries.values.associateBy { it.moduleName }
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.backend.js.ic.ICCache
import org.jetbrains.kotlin.ir.backend.js.ic.SerializedIcData
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
@@ -396,7 +397,7 @@ fun prepareAnalyzedSourceModule(
analyzer: AbstractAnalyzerWithCompilerReport,
icUseGlobalSignatures: Boolean = false,
icUseStdlibCache: Boolean = false,
icCache: Map<String, SerializedIcData> = emptyMap(),
icCache: Map<String, ICCache> = emptyMap(),
errorPolicy: ErrorTolerancePolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT,
): ModulesStructure {
val mainModule = MainModule.SourceFiles(files)
@@ -490,12 +491,12 @@ class ModulesStructure(
friendDependenciesPaths: Collection<String>,
val icUseGlobalSignatures: Boolean,
val icUseStdlibCache: Boolean,
val icCache: Map<String, SerializedIcData>,
val icCache: Map<String, ICCache>,
) {
val loweringsCacheProvider: LoweringsCacheProvider = when {
icUseStdlibCache -> object : LoweringsCacheProvider {
override fun cacheByPath(path: String): SerializedIcData? {
return icCache[path]
return icCache[path]?.serializedIcData
}
}
icUseGlobalSignatures -> EmptyLoweringsCacheProvider
+1
View File
@@ -239,6 +239,7 @@ val testDataDir = project(":js:js.translator").projectDir.resolve("testData")
projectTest(parallel = true) {
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = true)
// systemProperty("kotlin.js.ir.pir", "false")
inputs.dir(rootDir.resolve("compiler/cli/cli-common/resources")) // compiler.xml
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.common.output.writeAllTo
import org.jetbrains.kotlin.cli.js.resolve
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
@@ -27,7 +26,7 @@ import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
import org.jetbrains.kotlin.incremental.js.TranslationResultValue
import org.jetbrains.kotlin.ir.backend.js.ic.SerializedIcData
import org.jetbrains.kotlin.ir.backend.js.ic.ICCache
import org.jetbrains.kotlin.js.JavaScript
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
import org.jetbrains.kotlin.js.backend.ast.*
@@ -36,7 +35,10 @@ import org.jetbrains.kotlin.js.dce.DeadCodeElimination
import org.jetbrains.kotlin.js.dce.InputFile
import org.jetbrains.kotlin.js.dce.InputResource
import org.jetbrains.kotlin.js.engine.loadFiles
import org.jetbrains.kotlin.js.facade.*
import org.jetbrains.kotlin.js.facade.K2JSTranslator
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.js.parser.parse
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapError
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapLocationRemapper
@@ -178,6 +180,8 @@ abstract class BasicBoxTest(
return dependenciesSymbols.toSet() + dependenciesSymbols.flatMap { modules[it]!!.allTransitiveDependencies() }
}
val checkIC = modules.any { it.value.hasFilesToRecompile }
val orderedModules = DFS.topologicalOrder(modules.values) { module -> module.dependenciesSymbols.mapNotNull { modules[it] } }
val testPackage = if (runPlainBoxFunction) null else testFactory.testPackage
@@ -191,7 +195,7 @@ abstract class BasicBoxTest(
}
val testModuleName = if (runPlainBoxFunction) null else mainModuleName
val mainModule = modules[mainModuleName] ?: error("No module with name \"$mainModuleName\"")
val icCache = mutableMapOf<String, SerializedIcData>()
val icCache = mutableMapOf<String, ICCache>()
val generatedJsFiles = orderedModules.asReversed().mapNotNull { module ->
val dependencies = module.dependenciesSymbols.map { modules[it]?.outputFileName(outputDir) + ".meta.js" }
@@ -233,6 +237,7 @@ abstract class BasicBoxTest(
safeExternalBooleanDiagnostic,
skipMangleVerification,
abiVersion,
checkIC,
icCache
)
@@ -491,7 +496,8 @@ abstract class BasicBoxTest(
safeExternalBooleanDiagnostic: RuntimeDiagnostic?,
skipMangleVerification: Boolean,
abiVersion: KotlinAbiVersion,
icCache: MutableMap<String, SerializedIcData>
checkIC: Boolean,
icCache: MutableMap<String, ICCache>
) {
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
val testFiles = kotlinFiles.map { it.fileName }
@@ -546,6 +552,8 @@ abstract class BasicBoxTest(
safeExternalBooleanDiagnostic,
skipMangleVerification,
abiVersion,
checkIC,
recompile = false,
icCache
)
@@ -568,12 +576,13 @@ abstract class BasicBoxTest(
testPackage,
testFunction,
needsFullIrRuntime,
expectActualLinker
expectActualLinker,
icCache
)
}
}
private fun checkIncrementalCompilation(
protected open fun checkIncrementalCompilation(
sourceDirs: List<String>,
module: TestModule,
kotlinFiles: List<TestFile>,
@@ -591,7 +600,8 @@ abstract class BasicBoxTest(
testPackage: String?,
testFunction: String,
needsFullIrRuntime: Boolean,
expectActualLinker: Boolean
expectActualLinker: Boolean,
icCaches: MutableMap<String, ICCache>
) {
val sourceToTranslationUnit = hashMapOf<File, TranslationUnit>()
for (testFile in kotlinFiles) {
@@ -645,6 +655,8 @@ abstract class BasicBoxTest(
safeExternalBooleanDiagnostic = null,
skipMangleVerification = false,
abiVersion = KotlinAbiVersion.CURRENT,
incrementalCompilation = true,
recompile = true,
mutableMapOf()
)
@@ -729,7 +741,9 @@ abstract class BasicBoxTest(
safeExternalBooleanDiagnostic: RuntimeDiagnostic?,
skipMangleVerification: Boolean,
abiVersion: KotlinAbiVersion,
icCache: MutableMap<String, SerializedIcData>
incrementalCompilation: Boolean,
recompile: Boolean,
icCache: MutableMap<String, ICCache>
) {
val translator = K2JSTranslator(config, false)
val translationResult = translator.translateUnits(ExceptionThrowingReporter, units, mainCallParameters)
@@ -866,7 +880,7 @@ abstract class BasicBoxTest(
private fun createPsiFiles(fileNames: List<String>): List<KtFile> = fileNames.map(this::createPsiFile)
private fun createConfig(
protected fun createConfig(
sourceDirs: List<String>,
module: TestModule,
dependencies: List<String>,
@@ -1069,13 +1083,13 @@ abstract class BasicBoxTest(
}
}
private class TestFile(val fileName: String, val module: TestModule, val recompile: Boolean, val packageName: String) {
protected class TestFile(val fileName: String, val module: TestModule, val recompile: Boolean, val packageName: String) {
init {
module.files += this
}
}
private class TestModule(
protected class TestModule(
name: String,
dependencies: List<String>,
friends: List<String>,
@@ -1147,7 +1161,7 @@ abstract class BasicBoxTest(
protected val runTestInNashorn = getBoolean("kotlin.js.useNashorn")
const val TEST_MODULE = "JS_TESTS"
private const val DEFAULT_MODULE = "main"
const val DEFAULT_MODULE = "main"
private const val TEST_FUNCTION = "box"
private const val OLD_MODULE_SUFFIX = "-old"
@@ -5,15 +5,16 @@
package org.jetbrains.kotlin.js.test
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.backend.common.phaser.AnyNamedPhase
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.ic.SerializedIcData
import org.jetbrains.kotlin.ir.backend.js.ic.prepareSingleLibraryIcCache
import org.jetbrains.kotlin.ir.backend.js.ic.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
@@ -32,7 +33,7 @@ private val defaultRuntimeKlib = System.getProperty("kotlin.js.reduced.stdlib.pa
private val kotlinTestKLib = System.getProperty("kotlin.js.kotlin.test.path")
// TODO Cache on FS (requires bootstrap)
private val predefinedKlibHasIcCache = mutableMapOf<String, SerializedIcData?>(
private val predefinedKlibHasIcCache = mutableMapOf<String, ICCache?>(
File(fullRuntimeKlib).absolutePath to null,
File(kotlinTestKLib).absolutePath to null,
File(defaultRuntimeKlib).absolutePath to null
@@ -75,7 +76,7 @@ abstract class BasicIrBoxTest(
val perModule: Boolean = getBoolean("kotlin.js.ir.perModule")
// TODO Design incremental compilation for IR and add test support
override val incrementalCompilationChecksEnabled = false
override val incrementalCompilationChecksEnabled = true
private val compilationCache = mutableMapOf<String, String>()
@@ -111,9 +112,11 @@ abstract class BasicIrBoxTest(
safeExternalBooleanDiagnostic: RuntimeDiagnostic?,
skipMangleVerification: Boolean,
abiVersion: KotlinAbiVersion,
icCache: MutableMap<String, SerializedIcData>
incrementalCompilation: Boolean,
recompile: Boolean,
icCache: MutableMap<String, ICCache>
) {
val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file }
val filesToCompile = units.mapNotNull { (it as? TranslationUnit.SourceFile)?.file }
val runtimeKlibs = if (needsFullIrRuntime) listOf(fullRuntimeKlib, kotlinTestKLib) else listOf(defaultRuntimeKlib)
@@ -123,11 +126,17 @@ abstract class BasicIrBoxTest(
compilationCache[it] ?: error("Can't find compiled module for dependency $it")
}).map { File(it).absolutePath }.toMutableList()
val klibPath = outputFile.absolutePath.replace("_v5.js", "")
val klibPath = outputFile.canonicalPath.replace("_v5.js", "")
prepareRuntimePirCaches(config, icCache)
val actualOutputFile = outputFile.canonicalPath.let {
if (!isMainModule) klibPath else it
}
if (isMainModule && klibMainModule) {
if (incrementalCompilationChecksEnabled && incrementalCompilation) {
runtimeKlibs.forEach { createIcCache(it, runtimeKlibs, config, icCache) }
}
if (!recompile) { // In case of incremental recompilation we only rebuild caches, not klib itself
val module = prepareAnalyzedSourceModule(
config.project,
filesToCompile,
@@ -143,14 +152,16 @@ abstract class BasicIrBoxTest(
nopack = true,
jsOutputName = null
)
allKlibPaths += File(klibPath).absolutePath
}
val actualOutputFile = outputFile.absolutePath.let {
if (!isMainModule) klibPath else it
val klibCannonPath = File(klibPath).canonicalPath
if (incrementalCompilation) {
icCache[klibCannonPath] = createIcCache(klibCannonPath, allKlibPaths + klibCannonPath, config, icCache)
}
compilationCache[outputFile.name.replace(".js", ".meta.js")] = actualOutputFile
if (isMainModule) {
logger.logFile("Output JS", outputFile)
@@ -171,47 +182,27 @@ abstract class BasicIrBoxTest(
PhaseConfig(jsPhases)
}
fun prepareModule(allowIc: Boolean): ModulesStructure {
val useIc = runIcMode && allowIc
@Suppress("NAME_SHADOWING")
val icCache = if (useIc) icCache else emptyMap()
return if (!klibMainModule) {
prepareAnalyzedSourceModule(
config.project,
filesToCompile,
config.configuration,
allKlibPaths,
emptyList(),
AnalyzerWithCompilerReport(config.configuration),
icUseGlobalSignatures = useIc,
icUseStdlibCache = useIc,
icCache = icCache
)
} else {
ModulesStructure(
config.project,
MainModule.Klib(klibPath),
config.configuration,
allKlibPaths,
emptyList(),
icUseGlobalSignatures = useIc,
icUseStdlibCache = useIc,
icCache = icCache
)
}
}
val module = ModulesStructure(
config.project,
MainModule.Klib(klibPath),
config.configuration,
allKlibPaths + klibCannonPath,
emptyList(),
icUseGlobalSignatures = runIcMode,
icUseStdlibCache = runIcMode,
icCache = icCache
)
if (!skipRegularMode) {
val module = prepareModule(true)
val irFactory = if (lowerPerModule) PersistentIrFactory() else IrFactoryImpl
val compiledModule = compile(
module,
phaseConfig = phaseConfig,
irFactory = irFactory,
irFactory = IrFactoryImpl,
mainArguments = mainCallParameters.run { if (shouldBeGenerated()) arguments() else null },
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction))),
generateFullJs = true,
generateDceJs = runIrDce,
dceDriven = false,
es6mode = runEs6Mode,
multiModule = splitPerModule || perModule,
propertyLazyInitialization = propertyLazyInitialization,
@@ -221,7 +212,10 @@ abstract class BasicIrBoxTest(
verifySignatures = !skipMangleVerification,
)
compiledModule.outputs!!.writeTo(outputFile, config)
val jsOutputFile = if (recompile) File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js")
else outputFile
compiledModule.outputs!!.writeTo(jsOutputFile, config)
compiledModule.outputsAfterDce?.writeTo(dceOutputFile, config)
@@ -232,54 +226,127 @@ abstract class BasicIrBoxTest(
}
}
if (runIrPir && !skipDceDriven) {
val module = prepareModule(false)
compile(
if (runIrPir) {
val compiledModule = compile(
module,
phaseConfig = phaseConfig,
irFactory = PersistentIrFactory(),
mainArguments = mainCallParameters.run { if (shouldBeGenerated()) arguments() else null },
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction))),
generateFullJs = true,
generateDceJs = runIrDce,
dceDriven = true,
es6mode = runEs6Mode,
multiModule = splitPerModule || perModule,
propertyLazyInitialization = propertyLazyInitialization,
lowerPerModule = lowerPerModule,
safeExternalBoolean = safeExternalBoolean,
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
verifySignatures = !skipMangleVerification
).outputs!!.writeTo(pirOutputFile, config)
verifySignatures = !skipMangleVerification,
)
compiledModule.outputs!!.writeTo(pirOutputFile, config)
}
} else {
val module = prepareAnalyzedSourceModule(
config.project,
filesToCompile,
config.configuration,
allKlibPaths,
emptyList(),
AnalyzerWithCompilerReport(config.configuration)
)
generateKLib(
module,
irFactory = IrFactoryImpl,
outputKlibPath = actualOutputFile,
nopack = true,
verifySignatures = !skipMangleVerification,
abiVersion = abiVersion,
null
)
if (runIcMode) {
icCache[actualOutputFile] = createPirCache(actualOutputFile, allKlibPaths + actualOutputFile, config, icCache)
}
logger.logFile("Output klib", File(actualOutputFile))
compilationCache[outputFile.name.replace(".js", ".meta.js")] = actualOutputFile
}
}
override fun checkIncrementalCompilation(
sourceDirs: List<String>,
module: TestModule,
kotlinFiles: List<TestFile>,
dependencies: List<String>,
allDependencies: List<String>,
friends: List<String>,
multiModule: Boolean,
tmpDir: File,
remap: Boolean,
outputFile: File,
outputPrefixFile: File?,
outputPostfixFile: File?,
mainCallParameters: MainCallParameters,
incrementalData: IncrementalData,
testPackage: String?,
testFunction: String,
needsFullIrRuntime: Boolean,
expectActualLinker: Boolean,
icCaches: MutableMap<String, ICCache>
) {
val isMainModule = module.name == DEFAULT_MODULE || module.name == TEST_MODULE
val cacheKey = outputFile.canonicalPath.replace("_v5.js", "")
private fun createPirCache(path: String, allKlibPaths: Collection<String>, config: JsConfig, icCache: Map<String, SerializedIcData>): SerializedIcData {
val icCache = icCaches[cacheKey] ?: error("No IC data found for module ${module.name}")
val dirtyFiles = mutableListOf<String>()
val oldBinaryAsts = mutableMapOf<String, ByteArray>()
for (testFile in kotlinFiles) {
if (testFile.recompile) {
val fileName = testFile.fileName
oldBinaryAsts[fileName] = icCache.dataProvider.binaryAst(fileName)
icCache.dataConsumer.invalidateForFile(fileName)
dirtyFiles.add(fileName)
}
}
val recompiledOutputFile = File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js")
val recompiledMinOutputFile = File(recompiledOutputFile.parentFile, recompiledOutputFile.nameWithoutExtension + "-min.js")
val recompiledPirOutputFile = File(recompiledOutputFile.parentFile, recompiledOutputFile.nameWithoutExtension + "-pir.js")
val recompiledConfig = createConfig(
sourceDirs,
module,
dependencies,
allDependencies,
friends,
multiModule,
tmpDir,
null,
expectActualLinker,
ErrorTolerancePolicy.DEFAULT
)
translateFiles(
dirtyFiles.map { TranslationUnit.SourceFile(createPsiFile(it)) },
outputFile,
recompiledMinOutputFile,
recompiledPirOutputFile,
recompiledConfig,
outputPrefixFile,
outputPostfixFile,
mainCallParameters,
incrementalData,
remap,
testPackage,
testFunction,
needsFullIrRuntime,
isMainModule,
skipDceDriven = true,
splitPerModule = false, // TODO??
propertyLazyInitialization = false, // ??
safeExternalBoolean = false,
safeExternalBooleanDiagnostic = null,
skipMangleVerification = false,
KotlinAbiVersion.CURRENT,
incrementalCompilation = true,
recompile = true,
icCaches
)
val newBinaryAsts = dirtyFiles.associateWith { icCache.dataProvider.binaryAst(it) }
for (file in dirtyFiles) {
val oldBinaryAst = oldBinaryAsts[file]
val newBinaryAst = newBinaryAsts[file]
assert(oldBinaryAst.contentEquals(newBinaryAst)) { "Binary AST changed after recompilation for file $file" }
}
if (isMainModule) {
val originalOutput = FileUtil.loadFile(outputFile)
val recompiledOutput = FileUtil.loadFile(recompiledOutputFile)
assertEquals("Output file changed after recompilation", originalOutput, recompiledOutput)
}
}
private fun createPirCache(path: String, allKlibPaths: Collection<String>, config: JsConfig, icCache: Map<String, ICCache>): ICCache {
val icData = predefinedKlibHasIcCache[path] ?: prepareSingleLibraryIcCache(
project = project,
configuration = config.configuration,
@@ -295,7 +362,23 @@ abstract class BasicIrBoxTest(
return icData
}
private fun prepareRuntimePirCaches(config: JsConfig, icCache: MutableMap<String, SerializedIcData>) {
@Suppress("UNUSED_PARAMETER")
private fun createIcCache(path: String, allKlibPaths: Collection<String>, config: JsConfig, icCache: Map<String, ICCache>): ICCache {
fun prepare(): ICCache {
return ICCache(PersistentCacheProvider.EMPTY, PersistentCacheConsumer.EMPTY, SerializedIcData(emptyList()))
}
val icData = predefinedKlibHasIcCache[path] ?: prepare()
if (path in predefinedKlibHasIcCache) {
predefinedKlibHasIcCache[path] = icData
}
return icData
}
private fun prepareRuntimePirCaches(config: JsConfig, icCache: MutableMap<String, ICCache>) {
if (!runIcMode) return
val defaultRuntimePath = File(defaultRuntimeKlib).canonicalPath