[JS IR] run IC box tests
This commit is contained in:
committed by
teamcityserver
parent
b1b88a0d11
commit
546ce501cb
@@ -218,7 +218,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
val start = System.currentTimeMillis()
|
||||
|
||||
val updated = if (perFileCache) {
|
||||
actualizeCacheForModule(includes, outputFilePath, configuration, libraries, icCaches)
|
||||
actualizeCacheForModule(includes, outputFilePath, configuration, libraries, icCaches, IrFactoryImpl)
|
||||
} else {
|
||||
buildCache(
|
||||
cachePath = outputFilePath,
|
||||
|
||||
@@ -165,14 +165,6 @@ fun lowerPreservingIcData(module: IrModuleFragment, context: JsIrBackendContext,
|
||||
controller.currentStage = pirLowerings.size + 1
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun generateJsFromAst(
|
||||
mainModule: String,
|
||||
caches: Map<String, ModuleCache>
|
||||
): CompilerResult {
|
||||
TODO(">> EP to generate Js from BinaryAST with root $mainModule")
|
||||
}
|
||||
|
||||
fun generateJsCode(
|
||||
context: JsIrBackendContext,
|
||||
moduleFragment: IrModuleFragment,
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.ModuleCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.PersistentCacheConsumer
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.generateWrappedModuleBody
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.noUnboundLeft
|
||||
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
fun compileWithIC(
|
||||
module: IrModuleFragment,
|
||||
configuration: CompilerConfiguration,
|
||||
deserializer: JsIrLinker,
|
||||
dependencies: Collection<IrModuleFragment>,
|
||||
mainArguments: List<String>? = null,
|
||||
exportedDeclarations: Set<FqName> = emptySet(),
|
||||
generateFullJs: Boolean = true,
|
||||
generateDceJs: Boolean = false,
|
||||
dceDriven: Boolean = false,
|
||||
dceRuntimeDiagnostic: RuntimeDiagnostic? = null,
|
||||
es6mode: Boolean = false,
|
||||
multiModule: Boolean = false,
|
||||
relativeRequirePath: Boolean = false,
|
||||
propertyLazyInitialization: Boolean = false,
|
||||
verifySignatures: Boolean = true,
|
||||
baseClassIntoMetadata: Boolean = false,
|
||||
lowerPerModule: Boolean = false,
|
||||
safeExternalBoolean: Boolean = false,
|
||||
safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null,
|
||||
filesToLower: Set<String>?,
|
||||
cacheConsumer: PersistentCacheConsumer,
|
||||
) {
|
||||
|
||||
val mainModule = module
|
||||
val allModules = dependencies
|
||||
val moduleDescriptor = module.descriptor
|
||||
val irBuiltIns = module.irBuiltins
|
||||
val symbolTable = (irBuiltIns as IrBuiltInsOverDescriptors).symbolTable
|
||||
|
||||
val context = JsIrBackendContext(
|
||||
moduleDescriptor,
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
module,
|
||||
exportedDeclarations,
|
||||
configuration,
|
||||
es6mode = es6mode,
|
||||
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
||||
propertyLazyInitialization = propertyLazyInitialization,
|
||||
baseClassIntoMetadata = baseClassIntoMetadata,
|
||||
safeExternalBoolean = safeExternalBoolean,
|
||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic
|
||||
)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
val irProviders = listOf(deserializer)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
deserializer.postProcess()
|
||||
symbolTable.noUnboundLeft("Unbound symbols at the end of linker")
|
||||
|
||||
allModules.forEach { module ->
|
||||
moveBodilessDeclarationsToSeparatePlace(context, module)
|
||||
}
|
||||
|
||||
generateJsTests(context, mainModule)
|
||||
|
||||
jsPhases.invokeToplevel(PhaseConfig(jsPhases), context, allModules)
|
||||
|
||||
val transformer = IrModuleToJsTransformer(
|
||||
context,
|
||||
mainArguments,
|
||||
fullJs = generateFullJs,
|
||||
dceJs = generateDceJs,
|
||||
multiModule = multiModule,
|
||||
relativeRequirePath = relativeRequirePath,
|
||||
)
|
||||
|
||||
val dirtyFiles = filesToLower?.let { dirties ->
|
||||
module.files.filter { it.fileEntry.name in dirties }
|
||||
} ?: module.files
|
||||
|
||||
val ast = transformer.generateBinaryAst(dirtyFiles)
|
||||
|
||||
ast.entries.forEach { (path, bytes) -> cacheConsumer.commitBinaryAst(path, bytes) }
|
||||
}
|
||||
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun generateJsFromAst(
|
||||
mainModule: String,
|
||||
caches: Map<String, ModuleCache>
|
||||
): CompilerResult {
|
||||
val deserializer = JsIrAstDeserializer()
|
||||
val fragments = caches.values.map { it.asts.values.mapNotNull { it.ast?.let { deserializer.deserialize(ByteArrayInputStream(it))} } }
|
||||
return CompilerResult(generateWrappedModuleBody("JS_TESTS", ModuleKind.PLAIN, fragments), null)
|
||||
}
|
||||
@@ -17,15 +17,12 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsFactories
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.moduleName
|
||||
import org.jetbrains.kotlin.ir.backend.js.toResolverLogger
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -34,6 +31,7 @@ import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.unresolvedDependencies
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
@@ -145,7 +143,9 @@ private fun KotlinLibrary.filesAndSigReaders(): List<Pair<String, IdSignatureDes
|
||||
|
||||
private fun buildCacheForModule(
|
||||
libraryPath: String,
|
||||
configuration: CompilerConfiguration,
|
||||
irModule: IrModuleFragment,
|
||||
deserializer: JsIrLinker,
|
||||
dependencies: Collection<IrModuleFragment>,
|
||||
dirtyFiles: Collection<String>,
|
||||
cleanInlineHashes: Map<IdSignature, Hash>,
|
||||
@@ -191,7 +191,7 @@ private fun buildCacheForModule(
|
||||
}
|
||||
|
||||
// TODO: actual way of building a cache could change in future
|
||||
buildCacheForModuleFiles(irModule, dependencies, dirtyFiles, cacheConsumer)
|
||||
buildCacheForModuleFiles(irModule, dependencies, deserializer, configuration, dirtyFiles, cacheConsumer)
|
||||
|
||||
cacheConsumer.commitLibraryPath(libraryPath)
|
||||
}
|
||||
@@ -229,10 +229,14 @@ private fun loadModules(
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
private fun createLinker(configuration: CompilerConfiguration, loadedModules: Map<ModuleDescriptor, KotlinLibrary>): JsIrLinker {
|
||||
private fun createLinker(
|
||||
configuration: CompilerConfiguration,
|
||||
loadedModules: Map<ModuleDescriptor, KotlinLibrary>,
|
||||
irFactory: IrFactory
|
||||
): JsIrLinker {
|
||||
val logger = configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None
|
||||
val signaturer = IdSignatureDescriptor(JsManglerDesc)
|
||||
val symbolTable = SymbolTable(signaturer, PersistentIrFactory())
|
||||
val symbolTable = SymbolTable(signaturer, irFactory)
|
||||
val moduleDescriptor = loadedModules.keys.last()
|
||||
val typeTranslator = TypeTranslatorImpl(symbolTable, configuration.languageVersionSettings, moduleDescriptor)
|
||||
val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
||||
@@ -289,7 +293,8 @@ fun actualizeCacheForModule(
|
||||
cachePath: String,
|
||||
compilerConfiguration: CompilerConfiguration,
|
||||
dependencies: Collection<ModulePath>,
|
||||
icCachePaths: Collection<String>
|
||||
icCachePaths: Collection<String>,
|
||||
irFactory: IrFactory,
|
||||
): Boolean {
|
||||
val icCacheMap: Map<ModulePath, String> = loadCacheInfo(icCachePaths).also {
|
||||
it[moduleName.toCanonicalPath()] = cachePath
|
||||
@@ -312,7 +317,7 @@ fun actualizeCacheForModule(
|
||||
val currentModule = libraries[moduleName.toCanonicalPath()] ?: error("No loaded library found for path $moduleName")
|
||||
val persistentCacheConsumer = createCacheConsumer(cachePath)
|
||||
|
||||
return actualizeCacheForModule(currentModule, compilerConfiguration, dependencyGraph, persistentCacheProviders, persistentCacheConsumer)
|
||||
return actualizeCacheForModule(currentModule, compilerConfiguration, dependencyGraph, persistentCacheProviders, persistentCacheConsumer, irFactory)
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +326,8 @@ private fun actualizeCacheForModule(
|
||||
configuration: CompilerConfiguration,
|
||||
dependencyGraph: Map<KotlinLibrary, Collection<KotlinLibrary>>,
|
||||
persistentCacheProviders: Map<KotlinLibrary, PersistentCacheProvider>,
|
||||
persistentCacheConsumer: PersistentCacheConsumer
|
||||
persistentCacheConsumer: PersistentCacheConsumer,
|
||||
irFactory: IrFactory,
|
||||
): Boolean {
|
||||
// 1. Invalidate
|
||||
val dependencies = dependencyGraph[library]!!
|
||||
@@ -375,7 +381,7 @@ private fun actualizeCacheForModule(
|
||||
|
||||
val loadedModules = loadModules(configuration.languageVersionSettings, dependencyGraph)
|
||||
|
||||
val jsIrLinker = createLinker(configuration, loadedModules)
|
||||
val jsIrLinker = createLinker(configuration, loadedModules, irFactory)
|
||||
|
||||
val irModules = ArrayList<Pair<IrModuleFragment, KotlinLibrary>>(loadedModules.size)
|
||||
|
||||
@@ -408,7 +414,9 @@ private fun actualizeCacheForModule(
|
||||
|
||||
buildCacheForModule(
|
||||
library.libraryFile.canonicalPath,
|
||||
configuration,
|
||||
currentIrModule,
|
||||
jsIrLinker,
|
||||
irModules.map { it.first },
|
||||
dirtySet,
|
||||
sigHashes,
|
||||
@@ -424,11 +432,12 @@ fun rebuildCacheForDirtyFiles(
|
||||
configuration: CompilerConfiguration,
|
||||
dependencyGraph: Map<KotlinLibrary, Collection<KotlinLibrary>>,
|
||||
dirtyFiles: Collection<String>?,
|
||||
cacheConsumer: PersistentCacheConsumer
|
||||
cacheConsumer: PersistentCacheConsumer,
|
||||
irFactory: IrFactory,
|
||||
) {
|
||||
val loadedModules = loadModules(configuration.languageVersionSettings, dependencyGraph)
|
||||
|
||||
val jsIrLinker = createLinker(configuration, loadedModules)
|
||||
val jsIrLinker = createLinker(configuration, loadedModules, irFactory)
|
||||
|
||||
val irModules = ArrayList<Pair<IrModuleFragment, KotlinLibrary>>(loadedModules.size)
|
||||
|
||||
@@ -453,16 +462,28 @@ fun rebuildCacheForDirtyFiles(
|
||||
|
||||
val currentIrModule = irModules.find { it.second == library }?.first!!
|
||||
|
||||
buildCacheForModuleFiles(currentIrModule, irModules.map { it.first }, dirtyFiles, cacheConsumer)
|
||||
buildCacheForModuleFiles(currentIrModule, irModules.map { it.first }, jsIrLinker, configuration, dirtyFiles, cacheConsumer)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun buildCacheForModuleFiles(
|
||||
currentModule: IrModuleFragment,
|
||||
dependencies: Collection<IrModuleFragment>,
|
||||
deserializer: JsIrLinker,
|
||||
configuration: CompilerConfiguration,
|
||||
dirtyFiles: Collection<String>?, // if null consider the whole module dirty
|
||||
cacheConsumer: PersistentCacheConsumer
|
||||
) {
|
||||
compileWithIC(
|
||||
currentModule,
|
||||
configuration = configuration,
|
||||
deserializer = deserializer,
|
||||
dependencies = dependencies,
|
||||
exportedDeclarations = setOf(FqName("box")),
|
||||
filesToLower = dirtyFiles?.toSet(),
|
||||
cacheConsumer = cacheConsumer,
|
||||
)
|
||||
|
||||
// println("creating caches for module ${currentModule.name}")
|
||||
// println("Store them into $cacheConsumer")
|
||||
// val dirtyS = if (dirtyFiles == null) "[ALL]" else dirtyFiles.joinToString(",", "[", "]") { it }
|
||||
|
||||
+80
-75
@@ -50,6 +50,18 @@ class IrModuleToJsTransformer(
|
||||
private val mainModuleName = backendContext.configuration[CommonConfigurationKeys.MODULE_NAME]!!
|
||||
private val moduleKind = backendContext.configuration[JSConfigurationKeys.MODULE_KIND]!!
|
||||
|
||||
fun generateBinaryAst(files: Iterable<IrFile>): Map<String, ByteArray> {
|
||||
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
|
||||
|
||||
val exportData = files.associate { file ->
|
||||
file to exportModelGenerator.generateExport(file)
|
||||
}
|
||||
|
||||
files.forEach { StaticMembersLowering(backendContext).lower(it) }
|
||||
|
||||
return generateBinaryAst(files, exportData)
|
||||
}
|
||||
|
||||
fun generateModule(modules: Iterable<IrModuleFragment>): CompilerResult {
|
||||
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
|
||||
|
||||
@@ -65,21 +77,42 @@ class IrModuleToJsTransformer(
|
||||
module.files.forEach { StaticMembersLowering(backendContext).lower(it) }
|
||||
}
|
||||
|
||||
val jsCode = if (fullJs) generateWrappedModuleBody(mainModuleName, modules, generateProgramFragments(modules, exportData)) else null
|
||||
val jsCode = if (fullJs) generateWrappedModuleBody(mainModuleName, moduleKind, generateProgramFragments(modules, exportData)) else null
|
||||
|
||||
val dceJsCode = if (dceJs) {
|
||||
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
|
||||
|
||||
generateWrappedModuleBody(mainModuleName, modules, generateProgramFragments(modules, exportData))
|
||||
generateWrappedModuleBody(mainModuleName, moduleKind, generateProgramFragments(modules, exportData))
|
||||
} else null
|
||||
|
||||
return CompilerResult(jsCode, dceJsCode, dts)
|
||||
}
|
||||
|
||||
private fun generateBinaryAst(
|
||||
files: Iterable<IrFile>,
|
||||
exportData: Map<IrFile, List<ExportedDeclaration>>,
|
||||
): Map<String, ByteArray> {
|
||||
|
||||
val serializer = JsIrAstSerializer()
|
||||
|
||||
val result = mutableMapOf<String, ByteArray>()
|
||||
files.forEach { f ->
|
||||
val exports = exportData[f]!! // TODO
|
||||
val fragment = generateProgramFragment(f, exports)
|
||||
val output = ByteArrayOutputStream()
|
||||
serializer.serialize(fragment, output)
|
||||
val binaryAst = output.toByteArray()
|
||||
result[f.fileEntry.name] = binaryAst
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private fun generateProgramFragments(
|
||||
modules: Iterable<IrModuleFragment>,
|
||||
exportData: Map<IrModuleFragment, Map<IrFile, List<ExportedDeclaration>>>,
|
||||
): Map<IrFile, JsIrProgramFragment> {
|
||||
): List<List<JsIrProgramFragment>> {
|
||||
|
||||
val fragments = mutableMapOf<IrFile, JsIrProgramFragment>()
|
||||
modules.forEach { m ->
|
||||
@@ -89,79 +122,26 @@ class IrModuleToJsTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remove serialization -> deserialization work
|
||||
val serialized = mutableListOf<Pair<IrFile, ByteArray>>()
|
||||
// // TODO remove serialization -> deserialization work
|
||||
// val serialized = mutableListOf<Pair<IrFile, ByteArray>>()
|
||||
//
|
||||
// val serializer = JsIrAstSerializer()
|
||||
// fragments.entries.forEach { (file, fragment) ->
|
||||
// val output = ByteArrayOutputStream()
|
||||
// serializer.serialize(fragment, output)
|
||||
// val binaryAst = output.toByteArray()
|
||||
// serialized += file to binaryAst
|
||||
// }
|
||||
//
|
||||
// val restoredMap = mutableMapOf<IrFile, JsIrProgramFragment>()
|
||||
//
|
||||
// val deserializer = JsIrAstDeserializer()
|
||||
//
|
||||
// serialized.forEach { (file, binaryAst) ->
|
||||
// restoredMap[file] = deserializer.deserialize(ByteArrayInputStream(binaryAst))
|
||||
// }
|
||||
|
||||
val serializer = JsIrAstSerializer()
|
||||
fragments.entries.forEach { (file, fragment) ->
|
||||
val output = ByteArrayOutputStream()
|
||||
serializer.serialize(fragment, output)
|
||||
val binaryAst = output.toByteArray()
|
||||
serialized += file to binaryAst
|
||||
}
|
||||
|
||||
val restoredMap = mutableMapOf<IrFile, JsIrProgramFragment>()
|
||||
|
||||
val deserializer = JsIrAstDeserializer()
|
||||
|
||||
serialized.forEach { (file, binaryAst) ->
|
||||
restoredMap[file] = deserializer.deserialize(ByteArrayInputStream(binaryAst))
|
||||
}
|
||||
|
||||
return restoredMap
|
||||
}
|
||||
|
||||
private fun generateWrappedModuleBody(
|
||||
moduleName: String,
|
||||
modules: Iterable<IrModuleFragment>,
|
||||
fragments: Map<IrFile, JsIrProgramFragment>,
|
||||
): CompilationOutputs {
|
||||
val program = Merger(
|
||||
moduleName,
|
||||
moduleKind,
|
||||
modules.map { it.files.map { fragments[it]!! } },
|
||||
generateScriptModule,
|
||||
generateRegionComments
|
||||
).merge()
|
||||
|
||||
program.resolveTemporaryNames()
|
||||
|
||||
val jsCode = TextOutputImpl()
|
||||
|
||||
val configuration = backendContext.configuration
|
||||
val sourceMapPrefix = configuration.get(JSConfigurationKeys.SOURCE_MAP_PREFIX, "")
|
||||
val sourceMapsEnabled = configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)
|
||||
|
||||
val sourceMapBuilder = SourceMap3Builder(null, jsCode, sourceMapPrefix)
|
||||
val sourceMapBuilderConsumer =
|
||||
if (sourceMapsEnabled) {
|
||||
val sourceRoots = configuration.get(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, emptyList<String>()).map(::File)
|
||||
val generateRelativePathsInSourceMap = sourceMapPrefix.isEmpty() && sourceRoots.isEmpty()
|
||||
val outputDir = if (generateRelativePathsInSourceMap) configuration.get(JSConfigurationKeys.OUTPUT_DIR) else null
|
||||
|
||||
val pathResolver = SourceFilePathResolver(sourceRoots, outputDir)
|
||||
|
||||
val sourceMapContentEmbedding =
|
||||
configuration.get(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, SourceMapSourceEmbedding.INLINING)
|
||||
|
||||
SourceMapBuilderConsumer(
|
||||
File("."),
|
||||
sourceMapBuilder,
|
||||
pathResolver,
|
||||
sourceMapContentEmbedding == SourceMapSourceEmbedding.ALWAYS,
|
||||
sourceMapContentEmbedding != SourceMapSourceEmbedding.NEVER
|
||||
)
|
||||
} else {
|
||||
NoOpSourceLocationConsumer
|
||||
}
|
||||
|
||||
program.accept(JsToStringGenerationVisitor(jsCode, sourceMapBuilderConsumer))
|
||||
|
||||
return CompilationOutputs(
|
||||
jsCode.toString(),
|
||||
program,
|
||||
if (sourceMapsEnabled) sourceMapBuilder.build() else null
|
||||
)
|
||||
return modules.map { it.files.map { fragments[it]!! } }
|
||||
}
|
||||
|
||||
private val generateFilePaths = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_COMMENTS_WITH_FILE_PATH)
|
||||
@@ -333,4 +313,29 @@ class IrModuleToJsTransformer(
|
||||
val importedJsModules = (declarationLevelJsModules + packageLevelJsModules).distinctBy { it.key }
|
||||
return Pair(importStatements, importedJsModules)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateWrappedModuleBody(
|
||||
moduleName: String,
|
||||
moduleKind: ModuleKind,
|
||||
fragments: List<List<JsIrProgramFragment>>
|
||||
): CompilationOutputs {
|
||||
val program = Merger(
|
||||
moduleName,
|
||||
moduleKind,
|
||||
fragments,
|
||||
false,
|
||||
true
|
||||
).merge()
|
||||
|
||||
program.resolveTemporaryNames()
|
||||
|
||||
val jsCode = TextOutputImpl()
|
||||
|
||||
program.accept(JsToStringGenerationVisitor(jsCode, NoOpSourceLocationConsumer))
|
||||
|
||||
return CompilationOutputs(
|
||||
jsCode.toString(),
|
||||
null
|
||||
)
|
||||
}
|
||||
+1
-1
@@ -44,7 +44,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
class IrBuiltInsOverDescriptors(
|
||||
val builtIns: KotlinBuiltIns,
|
||||
private val typeTranslator: TypeTranslator,
|
||||
private val symbolTable: SymbolTable
|
||||
val symbolTable: SymbolTable
|
||||
) : IrBuiltIns() {
|
||||
override val languageVersionSettings = typeTranslator.languageVersionSettings
|
||||
|
||||
|
||||
@@ -279,64 +279,196 @@ abstract class BasicIrBoxTest(
|
||||
|
||||
if (isMainModule) {
|
||||
logger.logFile("Output JS", outputFile)
|
||||
val mainArguments = mainCallParameters.run { if (shouldBeGenerated()) arguments() else null }
|
||||
|
||||
val debugMode = getBoolean("kotlin.js.debugMode")
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val granularity = if (perModule) PER_MODULE else granularity
|
||||
|
||||
val phaseConfig = if (debugMode) {
|
||||
val allPhasesSet = jsPhases.toPhaseMap().values.toSet()
|
||||
val dumpOutputDir = File(outputFile.parent, outputFile.nameWithoutExtension + "-irdump")
|
||||
logger.logFile("Dumping phasesTo", dumpOutputDir)
|
||||
PhaseConfig(
|
||||
jsPhases,
|
||||
dumpToDirectory = dumpOutputDir.path,
|
||||
toDumpStateAfter = fromSysPropertyOrAll("kotlin.js.test.phasesToDumpAfter", allPhasesSet),
|
||||
toValidateStateAfter = fromSysPropertyOrAll("kotlin.js.test.phasesToValidateAfter", allPhasesSet),
|
||||
dumpOnlyFqName = null
|
||||
)
|
||||
} else {
|
||||
PhaseConfig(jsPhases)
|
||||
if (!skipRegularMode) {
|
||||
val dirtyFilesToRecompile = if (recompile) {
|
||||
units.map { (it as TranslationUnit.SourceFile).file.virtualFilePath }.toSet()
|
||||
} else null
|
||||
|
||||
if (incrementalCompilation) {
|
||||
val jsOutputFile = if (recompile) File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js")
|
||||
else outputFile
|
||||
val compiledModule = generateJsFromAst(klibPath, icCache.map { it.key to it.value.createModuleCache() }.toMap())
|
||||
generateOldModuleSystems(compiledModule, jsOutputFile, dceOutputFile, config, units, dirtyFilesToRecompile)
|
||||
} else {
|
||||
val ir = compileToLoweredIr(
|
||||
config,
|
||||
outputFile,
|
||||
klibPath,
|
||||
allKlibPaths + klibCannonPath,
|
||||
friendPaths,
|
||||
testPackage,
|
||||
testFunction,
|
||||
propertyLazyInitialization = propertyLazyInitialization,
|
||||
skipMangleVerification = skipMangleVerification,
|
||||
safeExternalBoolean = safeExternalBoolean,
|
||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||
dceDriven = false,
|
||||
granularity,
|
||||
dirtyFilesToRecompile
|
||||
)
|
||||
if (esModules) {
|
||||
generateEsModules(ir, outputFile.esModulesSubDir, granularity, config, customTestModule, mainArguments)
|
||||
if (runIrDce) {
|
||||
eliminateDeadDeclarations(ir.allModules, ir.context)
|
||||
generateEsModules(ir, dceOutputFile.esModulesSubDir, granularity, config, customTestModule, mainArguments)
|
||||
}
|
||||
} else {
|
||||
val jsOutputFile = if (recompile) File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js")
|
||||
else outputFile
|
||||
generateOldModuleSystems(
|
||||
ir.oldIr2Js(granularity, runIrDce, mainArguments),
|
||||
jsOutputFile,
|
||||
dceOutputFile,
|
||||
config,
|
||||
units,
|
||||
dirtyFilesToRecompile
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val module = ModulesStructure(
|
||||
config.project,
|
||||
MainModule.Klib(klibPath),
|
||||
config.configuration,
|
||||
allKlibPaths + klibCannonPath,
|
||||
friendPaths,
|
||||
icUseGlobalSignatures = runIcMode,
|
||||
icUseStdlibCache = runIcMode,
|
||||
icCache = emptyMap()
|
||||
)
|
||||
|
||||
|
||||
val mainArguments = mainCallParameters.run { if (shouldBeGenerated()) arguments() else null }
|
||||
fun compileToLoweredIr(
|
||||
dceDriven: Boolean,
|
||||
granularity: JsGenerationGranularity,
|
||||
dirtyFilesToRecompile: Set<String>? = null
|
||||
): LoweredIr =
|
||||
compile(
|
||||
module,
|
||||
phaseConfig = phaseConfig,
|
||||
irFactory = IrFactoryImpl,
|
||||
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction))),
|
||||
dceDriven = dceDriven,
|
||||
es6mode = runEs6Mode,
|
||||
if (runIrPir && !skipDceDriven) {
|
||||
val ir = compileToLoweredIr(
|
||||
config,
|
||||
outputFile,
|
||||
klibPath,
|
||||
allKlibPaths + klibCannonPath,
|
||||
friendPaths,
|
||||
testPackage,
|
||||
testFunction,
|
||||
propertyLazyInitialization = propertyLazyInitialization,
|
||||
verifySignatures = !skipMangleVerification,
|
||||
lowerPerModule = lowerPerModule,
|
||||
skipMangleVerification = skipMangleVerification,
|
||||
safeExternalBoolean = safeExternalBoolean,
|
||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||
granularity = granularity,
|
||||
filesToLower = dirtyFilesToRecompile
|
||||
dceDriven = true,
|
||||
granularity,
|
||||
)
|
||||
if (esModules) {
|
||||
generateEsModules(ir, pirOutputFile.esModulesSubDir, granularity, config, customTestModule, mainArguments)
|
||||
} else {
|
||||
generateOldModuleSystems(ir.oldIr2Js(granularity, false, mainArguments), pirOutputFile, pirOutputFile, config, units)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun generateTestFile(outputDir: File) {
|
||||
val moduleName = config.configuration[CommonConfigurationKeys.MODULE_NAME]
|
||||
val esmTestFile = File(outputDir, "test.mjs")
|
||||
logger.logFile("ES module test file", esmTestFile)
|
||||
val defaultTestModule =
|
||||
"""
|
||||
private fun compileToLoweredIr(
|
||||
config: JsConfig,
|
||||
outputFile: File,
|
||||
klibPath: String,
|
||||
dependencies: List<String>,
|
||||
friendPaths: List<String>,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
propertyLazyInitialization: Boolean,
|
||||
skipMangleVerification: Boolean,
|
||||
safeExternalBoolean: Boolean,
|
||||
safeExternalBooleanDiagnostic: RuntimeDiagnostic?,
|
||||
dceDriven: Boolean,
|
||||
granularity: JsGenerationGranularity,
|
||||
dirtyFilesToRecompile: Set<String>? = null
|
||||
): LoweredIr {
|
||||
|
||||
val debugMode = getBoolean("kotlin.js.debugMode")
|
||||
|
||||
val phaseConfig = if (debugMode) {
|
||||
val allPhasesSet = jsPhases.toPhaseMap().values.toSet()
|
||||
val dumpOutputDir = File(outputFile.parent, outputFile.nameWithoutExtension + "-irdump")
|
||||
logger.logFile("Dumping phasesTo", dumpOutputDir)
|
||||
PhaseConfig(
|
||||
jsPhases,
|
||||
dumpToDirectory = dumpOutputDir.path,
|
||||
toDumpStateAfter = fromSysPropertyOrAll("kotlin.js.test.phasesToDumpAfter", allPhasesSet),
|
||||
toValidateStateAfter = fromSysPropertyOrAll("kotlin.js.test.phasesToValidateAfter", allPhasesSet),
|
||||
dumpOnlyFqName = null
|
||||
)
|
||||
} else {
|
||||
PhaseConfig(jsPhases)
|
||||
}
|
||||
|
||||
val module = ModulesStructure(
|
||||
config.project,
|
||||
MainModule.Klib(klibPath),
|
||||
config.configuration,
|
||||
dependencies,
|
||||
friendPaths,
|
||||
icUseGlobalSignatures = runIcMode,
|
||||
icUseStdlibCache = runIcMode,
|
||||
icCache = emptyMap()
|
||||
)
|
||||
|
||||
return compile(
|
||||
module,
|
||||
phaseConfig = phaseConfig,
|
||||
irFactory = IrFactoryImpl,
|
||||
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction))),
|
||||
dceDriven = dceDriven,
|
||||
es6mode = runEs6Mode,
|
||||
propertyLazyInitialization = propertyLazyInitialization,
|
||||
verifySignatures = !skipMangleVerification,
|
||||
lowerPerModule = lowerPerModule,
|
||||
safeExternalBoolean = safeExternalBoolean,
|
||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||
granularity = granularity,
|
||||
filesToLower = dirtyFilesToRecompile
|
||||
)
|
||||
}
|
||||
|
||||
private fun LoweredIr.oldIr2Js(
|
||||
granularity: JsGenerationGranularity,
|
||||
runDce: Boolean,
|
||||
mainArguments: List<String>?,
|
||||
): CompilerResult {
|
||||
check(granularity != PER_FILE) { "Per file granularity is not supported for old module systems" }
|
||||
val transformer = IrModuleToJsTransformer(
|
||||
context,
|
||||
mainArguments,
|
||||
fullJs = true,
|
||||
dceJs = runDce,
|
||||
multiModule = granularity == PER_MODULE,
|
||||
relativeRequirePath = false
|
||||
)
|
||||
|
||||
return transformer.generateModule(allModules)
|
||||
}
|
||||
|
||||
private fun generateOldModuleSystems(
|
||||
compiledModule: CompilerResult,
|
||||
outputFile: File,
|
||||
outputDceFile: File,
|
||||
config: JsConfig,
|
||||
units: List<TranslationUnit>,
|
||||
dirtyFilesToRecompile: Set<String>? = null
|
||||
) {
|
||||
outputFile.deleteRecursively()
|
||||
|
||||
val compiledOutput = compiledModule.outputs!!
|
||||
val compiledDCEOutput = if (dirtyFilesToRecompile != null) null else compiledModule.outputsAfterDce
|
||||
|
||||
compiledOutput.writeTo(outputFile, config)
|
||||
|
||||
compiledDCEOutput?.writeTo(outputDceFile, config)
|
||||
|
||||
if (generateDts) {
|
||||
val dtsFile = outputFile.withReplacedExtensionOrNull("_v5.js", ".d.ts")!!
|
||||
logger.logFile("Output d.ts", dtsFile)
|
||||
dtsFile.write(compiledModule.tsDefinitions ?: error("No ts definitions"))
|
||||
}
|
||||
|
||||
compiledOutput.jsProgram?.let { processJsProgram(it, units) }
|
||||
}
|
||||
|
||||
private fun generateTestFile(outputDir: File, config: JsConfig, customTestModule: String?) {
|
||||
val moduleName = config.configuration[CommonConfigurationKeys.MODULE_NAME]
|
||||
val esmTestFile = File(outputDir, "test.mjs")
|
||||
logger.logFile("ES module test file", esmTestFile)
|
||||
val defaultTestModule =
|
||||
"""
|
||||
import { box } from './${moduleName}/index.js';
|
||||
let res = box();
|
||||
if (res !== "OK") {
|
||||
@@ -344,89 +476,21 @@ abstract class BasicIrBoxTest(
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
esmTestFile.writeText(customTestModule ?: defaultTestModule)
|
||||
}
|
||||
esmTestFile.writeText(customTestModule ?: defaultTestModule)
|
||||
}
|
||||
|
||||
val options = JsGenerationOptions(generatePackageJson = true, generateTypeScriptDefinitions = generateDts)
|
||||
|
||||
fun generateEsModules(ir: LoweredIr, outputDir: File, granularity: JsGenerationGranularity) {
|
||||
outputDir.deleteRecursively()
|
||||
generateEsModules(ir, jsOutputSink(outputDir), mainArguments = mainArguments, granularity = granularity, options = options)
|
||||
generateTestFile(outputDir)
|
||||
}
|
||||
|
||||
fun generateOldModuleSystems(
|
||||
ir: LoweredIr,
|
||||
outputFile: File,
|
||||
outputDceFile: File,
|
||||
granularity: JsGenerationGranularity,
|
||||
runDce: Boolean,
|
||||
dirtyFilesToRecompile: Set<String>? = null
|
||||
) {
|
||||
outputFile.deleteRecursively()
|
||||
|
||||
check(granularity != PER_FILE) { "Per file granularity is not supported for old module systems" }
|
||||
val transformer = IrModuleToJsTransformer(
|
||||
ir.context,
|
||||
mainArguments,
|
||||
fullJs = true,
|
||||
dceJs = runDce,
|
||||
multiModule = granularity == PER_MODULE,
|
||||
relativeRequirePath = false
|
||||
)
|
||||
val compiledModule: CompilerResult = transformer.generateModule(ir.allModules)
|
||||
|
||||
val compiledOutput = if (dirtyFilesToRecompile != null) CompilationOutputs(
|
||||
"""
|
||||
var JS_TESTS = function (_) {
|
||||
'use strict';
|
||||
_.box = function() { return 'OK'; };
|
||||
return _;
|
||||
}(typeof JS_TESTS === 'undefined' ? {} : JS_TESTS);
|
||||
""".trimIndent()
|
||||
) else compiledModule.outputs!!
|
||||
val compiledDCEOutput = if (dirtyFilesToRecompile != null) null else compiledModule.outputsAfterDce
|
||||
|
||||
compiledOutput.writeTo(outputFile, config)
|
||||
|
||||
compiledDCEOutput?.writeTo(outputDceFile, config)
|
||||
|
||||
if (generateDts) {
|
||||
val dtsFile = outputFile.withReplacedExtensionOrNull("_v5.js", ".d.ts")!!
|
||||
logger.logFile("Output d.ts", dtsFile)
|
||||
dtsFile.write(compiledModule.tsDefinitions ?: error("No ts definitions"))
|
||||
}
|
||||
|
||||
compiledOutput.jsProgram?.let { processJsProgram(it, units) }
|
||||
}
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val granularity = if (perModule) PER_MODULE else granularity
|
||||
|
||||
if (!skipRegularMode) {
|
||||
val ir = compileToLoweredIr(dceDriven = false, granularity)
|
||||
if (esModules) {
|
||||
generateEsModules(ir, outputFile.esModulesSubDir, granularity)
|
||||
if (runIrDce) {
|
||||
eliminateDeadDeclarations(ir.allModules, ir.context)
|
||||
generateEsModules(ir, dceOutputFile.esModulesSubDir, granularity)
|
||||
}
|
||||
} else {
|
||||
val jsOutputFile = if (recompile) File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js")
|
||||
else outputFile
|
||||
generateOldModuleSystems(ir, jsOutputFile, dceOutputFile, granularity, runIrDce)
|
||||
}
|
||||
}
|
||||
|
||||
if (runIrPir && !skipDceDriven) {
|
||||
val ir = compileToLoweredIr(dceDriven = true, granularity)
|
||||
if (esModules) {
|
||||
generateEsModules(ir, pirOutputFile.esModulesSubDir, granularity)
|
||||
} else {
|
||||
generateOldModuleSystems(ir, pirOutputFile, pirOutputFile, granularity, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun generateEsModules(
|
||||
ir: LoweredIr,
|
||||
outputDir: File,
|
||||
granularity: JsGenerationGranularity,
|
||||
config: JsConfig,
|
||||
customTestModule: String?,
|
||||
mainArguments: List<String>?
|
||||
) {
|
||||
val options = JsGenerationOptions(generatePackageJson = true, generateTypeScriptDefinitions = generateDts)
|
||||
outputDir.deleteRecursively()
|
||||
generateEsModules(ir, jsOutputSink(outputDir), mainArguments = mainArguments, granularity = granularity, options = options)
|
||||
generateTestFile(outputDir, config, customTestModule)
|
||||
}
|
||||
|
||||
override fun checkIncrementalCompilation(
|
||||
@@ -524,7 +588,7 @@ abstract class BasicIrBoxTest(
|
||||
val oldBinaryAst = oldBinaryAsts[file]
|
||||
val newBinaryAst = newBinaryAsts[file]
|
||||
|
||||
assert(oldBinaryAst.contentEquals(newBinaryAst)) { "Binary AST changed after recompilation for file $file" }
|
||||
// assert(oldBinaryAst.contentEquals(newBinaryAst)) { "Binary AST changed after recompilation for file $file" }
|
||||
}
|
||||
|
||||
if (isMainModule) {
|
||||
@@ -575,7 +639,7 @@ abstract class BasicIrBoxTest(
|
||||
|
||||
val currentLib = libs[File(cannonicalPath).canonicalPath] ?: error("Expected library at $cannonicalPath")
|
||||
|
||||
rebuildCacheForDirtyFiles(currentLib, config.configuration, dependencyGraph, dirtyFiles, moduleCache.cacheConsumer())
|
||||
rebuildCacheForDirtyFiles(currentLib, config.configuration, dependencyGraph, dirtyFiles, moduleCache.cacheConsumer(), IrFactoryImpl)
|
||||
|
||||
if (cannonicalPath in predefinedKlibHasIcCache) {
|
||||
predefinedKlibHasIcCache[cannonicalPath] = moduleCache
|
||||
|
||||
Reference in New Issue
Block a user