[JS IR IC] Do not read non modified JS into memory
Optimizaion: instead of reading all non modified JS files from the cache into the memory at once, the patch allows copying non-modified JS files from disk one by one during the compilation output writing routine.
This commit is contained in:
committed by
Space Team
parent
dd268d67ff
commit
75931fb9c8
@@ -77,6 +77,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsCodeGenerator
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsCodeGenerator
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputsBuilt
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
@@ -155,7 +156,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
return transformer.makeJsCodeGenerator(ir.allModules, mode)
|
return transformer.makeJsCodeGenerator(ir.allModules, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compileAndTransformIrNew(): CompilationOutputs {
|
fun compileAndTransformIrNew(): CompilationOutputsBuilt {
|
||||||
return makeJsCodeGenerator().generateJsCode(relativeRequirePath = true, outJsProgram = false)
|
return makeJsCodeGenerator().generateJsCode(relativeRequirePath = true, outJsProgram = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,7 +318,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val (outputs, rebuiltModules) = jsExecutableProducer.buildExecutable(arguments.irPerModule, outJsProgram = false)
|
val (outputs, rebuiltModules) = jsExecutableProducer.buildExecutable(arguments.irPerModule, outJsProgram = false)
|
||||||
outputs.write(outputDir, outputName, arguments.generateDts, moduleName, moduleKind)
|
outputs.writeAll(outputDir, outputName, arguments.generateDts, moduleName, moduleKind)
|
||||||
|
|
||||||
messageCollector.report(INFO, "Executable production duration (IC): ${System.currentTimeMillis() - beforeIc2Js}ms")
|
messageCollector.report(INFO, "Executable production duration (IC): ${System.currentTimeMillis() - beforeIc2Js}ms")
|
||||||
for ((event, duration) in jsExecutableProducer.getStopwatchLaps()) {
|
for ((event, duration) in jsExecutableProducer.getStopwatchLaps()) {
|
||||||
@@ -393,7 +394,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
|
|
||||||
messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms")
|
messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms")
|
||||||
|
|
||||||
outputs.write(outputDir, outputName, arguments.generateDts, moduleName, moduleKind)
|
outputs.writeAll(outputDir, outputName, arguments.generateDts, moduleName, moduleKind)
|
||||||
} catch (e: CompilationException) {
|
} catch (e: CompilationException) {
|
||||||
messageCollector.report(
|
messageCollector.report(
|
||||||
ERROR,
|
ERROR,
|
||||||
@@ -704,28 +705,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
return icCaches
|
return icCaches
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CompilationOutputs.write(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind) {
|
|
||||||
val outputFile = outputDir.resolve("$outputName.js")
|
|
||||||
outputFile.parentFile.mkdirs()
|
|
||||||
outputFile.write(this)
|
|
||||||
dependencies.forEach { (name, content) ->
|
|
||||||
outputDir.resolve("$name.js").let {
|
|
||||||
it.parentFile.mkdirs()
|
|
||||||
it.write(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (genDTS) {
|
|
||||||
val dtsFile = outputDir.resolve("$outputName.d.ts")
|
|
||||||
dtsFile.writeText(getFullTsDefinition(moduleName, moduleKind))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun File.write(outputs: CompilationOutputs) {
|
|
||||||
writeText(outputs.jsCode)
|
|
||||||
outputs.writeSourceMapIfPresent(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPlatformSpecificArgumentsAndServices(
|
override fun setupPlatformSpecificArgumentsAndServices(
|
||||||
configuration: CompilerConfiguration,
|
configuration: CompilerConfiguration,
|
||||||
arguments: K2JSCompilerArguments,
|
arguments: K2JSCompilerArguments,
|
||||||
|
|||||||
@@ -11,46 +11,24 @@ import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnb
|
|||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.toTypeScript
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
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.moveBodilessDeclarationsToSeparatePlace
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
|
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class CompilerResult(
|
class CompilerResult(
|
||||||
val outputs: Map<TranslationMode, CompilationOutputs>,
|
val outputs: Map<TranslationMode, CompilationOutputs>,
|
||||||
)
|
)
|
||||||
|
|
||||||
class CompilationOutputs(
|
|
||||||
val jsCode: String,
|
|
||||||
val tsDefinitions: TypeScriptFragment? = null,
|
|
||||||
val jsProgram: JsProgram? = null,
|
|
||||||
val sourceMap: String? = null,
|
|
||||||
val dependencies: Iterable<Pair<String, CompilationOutputs>> = emptyList()
|
|
||||||
) {
|
|
||||||
fun addDependencies(depends: Iterable<Pair<String, CompilationOutputs>>): CompilationOutputs {
|
|
||||||
return CompilationOutputs(jsCode, tsDefinitions, jsProgram, sourceMap, depends)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getFullTsDefinition(name: String, moduleKind: ModuleKind): String {
|
|
||||||
val allTsDefinitions = dependencies.mapNotNull { it.second.tsDefinitions } + listOfNotNull(tsDefinitions)
|
|
||||||
return allTsDefinitions.toTypeScript(name, moduleKind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoweredIr(
|
class LoweredIr(
|
||||||
val context: JsIrBackendContext,
|
val context: JsIrBackendContext,
|
||||||
val mainModule: IrModuleFragment,
|
val mainModule: IrModuleFragment,
|
||||||
@@ -163,11 +141,3 @@ fun compileIr(
|
|||||||
|
|
||||||
return LoweredIr(context, moduleFragment, allModules, moduleToName)
|
return LoweredIr(context, moduleFragment, allModules, moduleToName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CompilationOutputs.writeSourceMapIfPresent(outputJsFile: File) {
|
|
||||||
sourceMap?.let {
|
|
||||||
val mapFile = outputJsFile.resolveSibling("${outputJsFile.name}.map")
|
|
||||||
outputJsFile.appendText("\n//# sourceMappingURL=${mapFile.name}\n")
|
|
||||||
mapFile.writeText(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-4
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
@@ -96,11 +95,10 @@ class JsExecutableProducer(
|
|||||||
val mainModule = cachedMainModule.compileModule(mainModuleName, true)
|
val mainModule = cachedMainModule.compileModule(mainModuleName, true)
|
||||||
|
|
||||||
val cachedOtherModules = cachedProgram.dropLast(1)
|
val cachedOtherModules = cachedProgram.dropLast(1)
|
||||||
val dependencies = cachedOtherModules.map {
|
mainModule.dependencies = cachedOtherModules.map {
|
||||||
it.jsIrHeader.externalModuleName to it.compileModule(it.jsIrHeader.externalModuleName, false)
|
it.jsIrHeader.externalModuleName to it.compileModule(it.jsIrHeader.externalModuleName, false)
|
||||||
}
|
}
|
||||||
stopwatch.stop()
|
stopwatch.stop()
|
||||||
val compilationOut = mainModule.addDependencies(dependencies)
|
return BuildResult(mainModule, rebuildModules)
|
||||||
return BuildResult(compilationOut, rebuildModules)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-13
@@ -5,10 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CrossModuleReferences
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrModuleHeader
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class JsMultiModuleCache(private val moduleArtifacts: List<ModuleArtifact>) {
|
class JsMultiModuleCache(private val moduleArtifacts: List<ModuleArtifact>) {
|
||||||
@@ -99,17 +96,19 @@ class JsMultiModuleCache(private val moduleArtifacts: List<ModuleArtifact>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fetchCompiledJsCode(artifact: ModuleArtifact) = artifact.artifactsDir?.let { cacheDir ->
|
fun fetchCompiledJsCode(artifact: ModuleArtifact) = artifact.artifactsDir?.let { cacheDir ->
|
||||||
val jsCode = File(cacheDir, CACHED_MODULE_JS).ifExists { readText() }
|
val jsCodeFilePath = File(cacheDir, CACHED_MODULE_JS).ifExists { absolutePath }
|
||||||
val sourceMap = File(cacheDir, CACHED_MODULE_JS_MAP).ifExists { readText() }
|
val sourceMapFilePath = File(cacheDir, CACHED_MODULE_JS_MAP).ifExists { absolutePath }
|
||||||
val tsDefinitions = File(cacheDir, CACHED_MODULE_D_TS).ifExists { TypeScriptFragment(readText()) }
|
val tsDefinitionsFilePath = File(cacheDir, CACHED_MODULE_D_TS).ifExists { absolutePath }
|
||||||
jsCode?.let { CompilationOutputs(it, tsDefinitions, null, sourceMap) }
|
jsCodeFilePath?.let { CompilationOutputsCached(it, sourceMapFilePath, tsDefinitionsFilePath) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun commitCompiledJsCode(artifact: ModuleArtifact, compilationOutputs: CompilationOutputs) = artifact.artifactsDir?.let { cacheDir ->
|
fun commitCompiledJsCode(artifact: ModuleArtifact, compilationOutputs: CompilationOutputsBuilt) =
|
||||||
File(cacheDir, CACHED_MODULE_JS).writeIfNotNull(compilationOutputs.jsCode)
|
artifact.artifactsDir?.let { cacheDir ->
|
||||||
File(cacheDir, CACHED_MODULE_JS_MAP).writeIfNotNull(compilationOutputs.sourceMap)
|
val jsCodeFile = File(cacheDir, CACHED_MODULE_JS)
|
||||||
File(cacheDir, CACHED_MODULE_D_TS).writeIfNotNull(compilationOutputs.tsDefinitions?.raw)
|
val jsMapFile = File(cacheDir, CACHED_MODULE_JS_MAP)
|
||||||
}
|
compilationOutputs.writeJsCode(jsCodeFile, jsMapFile)
|
||||||
|
File(cacheDir, CACHED_MODULE_D_TS).writeIfNotNull(compilationOutputs.tsDefinitions?.raw)
|
||||||
|
}
|
||||||
|
|
||||||
fun loadProgramHeadersFromCache(): List<CachedModuleInfo> {
|
fun loadProgramHeadersFromCache(): List<CachedModuleInfo> {
|
||||||
return moduleArtifacts.map { artifact ->
|
return moduleArtifacts.map { artifact ->
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.export.toTypeScript
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
abstract class CompilationOutputs {
|
||||||
|
var dependencies: Collection<Pair<String, CompilationOutputs>> = emptyList()
|
||||||
|
|
||||||
|
abstract val tsDefinitions: TypeScriptFragment?
|
||||||
|
|
||||||
|
abstract val jsProgram: JsProgram?
|
||||||
|
|
||||||
|
abstract fun writeJsCode(outputJsFile: File, outputJsMapFile: File)
|
||||||
|
|
||||||
|
fun writeAll(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind): List<String> {
|
||||||
|
val writtenJsFiles = ArrayList<String>(dependencies.size + 1)
|
||||||
|
|
||||||
|
val outputJsFile = outputDir.resolve("$outputName.js")
|
||||||
|
|
||||||
|
outputJsFile.parentFile.mkdirs()
|
||||||
|
writeJsCode(outputJsFile, outputJsFile.mapForJsFile)
|
||||||
|
|
||||||
|
dependencies.forEach { (name, content) ->
|
||||||
|
outputDir.resolve("$name.js").let { depJsFile ->
|
||||||
|
depJsFile.parentFile.mkdirs()
|
||||||
|
content.writeJsCode(depJsFile, depJsFile.mapForJsFile)
|
||||||
|
writtenJsFiles += depJsFile.absolutePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writtenJsFiles += outputJsFile.absolutePath
|
||||||
|
|
||||||
|
if (genDTS) {
|
||||||
|
outputJsFile.dtsForJsFile.writeText(getFullTsDefinition(moduleName, moduleKind))
|
||||||
|
}
|
||||||
|
|
||||||
|
return writtenJsFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFullTsDefinition(moduleName: String, moduleKind: ModuleKind): String {
|
||||||
|
val allTsDefinitions = dependencies.mapNotNull { it.second.tsDefinitions } + listOfNotNull(tsDefinitions)
|
||||||
|
return allTsDefinitions.toTypeScript(moduleName, moduleKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val File.mapForJsFile
|
||||||
|
get() = resolveSibling("$name.map")
|
||||||
|
|
||||||
|
private val File.dtsForJsFile
|
||||||
|
get() = resolveSibling("$nameWithoutExtension.d.ts")
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompilationOutputsBuilt(
|
||||||
|
private val rawJsCode: String,
|
||||||
|
private val sourceMap: String?,
|
||||||
|
override val tsDefinitions: TypeScriptFragment?,
|
||||||
|
override val jsProgram: JsProgram?,
|
||||||
|
) : CompilationOutputs() {
|
||||||
|
override fun writeJsCode(outputJsFile: File, outputJsMapFile: File) {
|
||||||
|
var jsCodeWithSourceMap = rawJsCode
|
||||||
|
|
||||||
|
sourceMap?.let {
|
||||||
|
outputJsMapFile.writeText(it)
|
||||||
|
jsCodeWithSourceMap = "$jsCodeWithSourceMap\n//# sourceMappingURL=${outputJsMapFile.name}\n"
|
||||||
|
}
|
||||||
|
outputJsFile.writeText(jsCodeWithSourceMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompilationOutputsCached(
|
||||||
|
private val jsCodeFilePath: String,
|
||||||
|
private val sourceMapFilePath: String?,
|
||||||
|
private val tsDefinitionsFilePath: String?
|
||||||
|
) : CompilationOutputs() {
|
||||||
|
override val tsDefinitions: TypeScriptFragment?
|
||||||
|
get() = tsDefinitionsFilePath?.let { TypeScriptFragment(File(it).readText()) }
|
||||||
|
|
||||||
|
override val jsProgram: JsProgram?
|
||||||
|
get() = null
|
||||||
|
|
||||||
|
override fun writeJsCode(outputJsFile: File, outputJsMapFile: File) {
|
||||||
|
File(jsCodeFilePath).copyTo(outputJsFile, true)
|
||||||
|
|
||||||
|
sourceMapFilePath?.let {
|
||||||
|
File(it).copyTo(outputJsMapFile, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-8
@@ -81,7 +81,7 @@ class JsCodeGenerator(
|
|||||||
private val moduleKind: ModuleKind,
|
private val moduleKind: ModuleKind,
|
||||||
private val sourceMapsInfo: SourceMapsInfo?
|
private val sourceMapsInfo: SourceMapsInfo?
|
||||||
) {
|
) {
|
||||||
fun generateJsCode(relativeRequirePath: Boolean, outJsProgram: Boolean): CompilationOutputs {
|
fun generateJsCode(relativeRequirePath: Boolean, outJsProgram: Boolean): CompilationOutputsBuilt {
|
||||||
return generateWrappedModuleBody(
|
return generateWrappedModuleBody(
|
||||||
multiModule,
|
multiModule,
|
||||||
mainModuleName,
|
mainModuleName,
|
||||||
@@ -380,7 +380,7 @@ private fun generateWrappedModuleBody(
|
|||||||
sourceMapsInfo: SourceMapsInfo?,
|
sourceMapsInfo: SourceMapsInfo?,
|
||||||
relativeRequirePath: Boolean,
|
relativeRequirePath: Boolean,
|
||||||
outJsProgram: Boolean
|
outJsProgram: Boolean
|
||||||
): CompilationOutputs {
|
): CompilationOutputsBuilt {
|
||||||
if (multiModule) {
|
if (multiModule) {
|
||||||
// mutable container allows explicitly remove elements from itself,
|
// mutable container allows explicitly remove elements from itself,
|
||||||
// so we are able to help GC to free heavy JsIrModule objects
|
// so we are able to help GC to free heavy JsIrModule objects
|
||||||
@@ -398,7 +398,7 @@ private fun generateWrappedModuleBody(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dependencies = buildList(moduleToRef.size) {
|
mainModule.dependencies = buildList(moduleToRef.size) {
|
||||||
while (moduleToRef.isNotEmpty()) {
|
while (moduleToRef.isNotEmpty()) {
|
||||||
moduleToRef.removeFirst().let { (module, moduleRef) ->
|
moduleToRef.removeFirst().let { (module, moduleRef) ->
|
||||||
val moduleName = module.externalModuleName
|
val moduleName = module.externalModuleName
|
||||||
@@ -416,7 +416,7 @@ private fun generateWrappedModuleBody(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mainModule.addDependencies(dependencies)
|
return mainModule
|
||||||
} else {
|
} else {
|
||||||
return generateSingleWrappedModuleBody(
|
return generateSingleWrappedModuleBody(
|
||||||
mainModuleName,
|
mainModuleName,
|
||||||
@@ -437,7 +437,7 @@ fun generateSingleWrappedModuleBody(
|
|||||||
generateCallToMain: Boolean,
|
generateCallToMain: Boolean,
|
||||||
crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty(moduleKind),
|
crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty(moduleKind),
|
||||||
outJsProgram: Boolean = true
|
outJsProgram: Boolean = true
|
||||||
): CompilationOutputs {
|
): CompilationOutputsBuilt {
|
||||||
val program = Merger(
|
val program = Merger(
|
||||||
moduleName,
|
moduleName,
|
||||||
moduleKind,
|
moduleKind,
|
||||||
@@ -476,10 +476,10 @@ fun generateSingleWrappedModuleBody(
|
|||||||
|
|
||||||
program.accept(JsToStringGenerationVisitor(jsCode, sourceMapBuilderConsumer))
|
program.accept(JsToStringGenerationVisitor(jsCode, sourceMapBuilderConsumer))
|
||||||
|
|
||||||
return CompilationOutputs(
|
return CompilationOutputsBuilt(
|
||||||
jsCode.toString(),
|
jsCode.toString(),
|
||||||
|
sourceMapBuilder?.build(),
|
||||||
fragments.mapNotNull { it.dts }.ifNotEmpty { joinTypeScriptFragments() },
|
fragments.mapNotNull { it.dts }.ifNotEmpty { joinTypeScriptFragments() },
|
||||||
program.takeIf { outJsProgram },
|
program.takeIf { outJsProgram }
|
||||||
sourceMapBuilder?.build()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.backend.js.*
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
||||||
@@ -225,16 +226,6 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
writeText(ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, JS_MODULE_KIND, moduleName))
|
writeText(ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, JS_MODULE_KIND, moduleName))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeJsFile(name: String, text: String): String {
|
|
||||||
val moduleFileName = "./$name.js"
|
|
||||||
val file = File(jsDir, moduleFileName)
|
|
||||||
if (file.exists()) {
|
|
||||||
file.delete()
|
|
||||||
}
|
|
||||||
file.writeAsJsModule(text, moduleFileName)
|
|
||||||
return file.canonicalPath
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun prepareExternalJsFiles(): MutableList<String> {
|
private fun prepareExternalJsFiles(): MutableList<String> {
|
||||||
jsDir.invalidateDir()
|
jsDir.invalidateDir()
|
||||||
return testDir.filesInDir.mapNotNullTo(mutableListOf(MODULE_EMULATION_FILE)) { file ->
|
return testDir.filesInDir.mapNotNullTo(mutableListOf(MODULE_EMULATION_FILE)) { file ->
|
||||||
@@ -249,12 +240,15 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
|
|
||||||
private fun verifyJsCode(stepId: Int, mainModuleName: String, jsOutput: CompilationOutputs) {
|
private fun verifyJsCode(stepId: Int, mainModuleName: String, jsOutput: CompilationOutputs) {
|
||||||
val files = prepareExternalJsFiles()
|
val files = prepareExternalJsFiles()
|
||||||
jsOutput.dependencies.mapTo(files) { writeJsFile(it.first, it.second.jsCode) }
|
val compiledJsFiles = jsOutput.writeAll(jsDir, mainModuleName, true, mainModuleName, JS_MODULE_KIND)
|
||||||
files += writeJsFile(mainModuleName, jsOutput.jsCode)
|
for (jsCodeFile in compiledJsFiles) {
|
||||||
|
val jsFile = File(jsCodeFile)
|
||||||
|
jsFile.writeAsJsModule(jsFile.readText(), "./${jsFile.name}")
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
V8IrJsTestChecker.checkWithTestFunctionArgs(
|
V8IrJsTestChecker.checkWithTestFunctionArgs(
|
||||||
files = files,
|
files = files + compiledJsFiles,
|
||||||
testModuleName = "./$mainModuleName.js",
|
testModuleName = "./$mainModuleName.js",
|
||||||
testPackageName = null,
|
testPackageName = null,
|
||||||
testFunctionName = BOX_FUNCTION_NAME,
|
testFunctionName = BOX_FUNCTION_NAME,
|
||||||
@@ -269,11 +263,16 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun verifyDTS(stepId: Int, testInfo: List<TestStepInfo>, jsOutput: CompilationOutputs) {
|
private fun verifyDTS(stepId: Int, testInfo: List<TestStepInfo>) {
|
||||||
for (info in testInfo) {
|
for (info in testInfo) {
|
||||||
val expectedDTS = info.expectedDTS ?: continue
|
val expectedDTS = info.expectedDTS ?: continue
|
||||||
val output = jsOutput.dependencies.find { it.first == info.moduleName }?.second ?: jsOutput
|
|
||||||
val gotDTS = output.getFullTsDefinition(info.moduleName, JS_MODULE_KIND)
|
val dtsFile = jsDir.resolve("${File(info.modulePath).nameWithoutExtension}.d.ts")
|
||||||
|
JUnit4Assertions.assertTrue(dtsFile.exists()) {
|
||||||
|
"Cannot find d.ts (${dtsFile.absolutePath}) file for module ${info.moduleName} at step $stepId"
|
||||||
|
}
|
||||||
|
|
||||||
|
val gotDTS = dtsFile.readText()
|
||||||
JUnit4Assertions.assertEquals(expectedDTS, gotDTS) {
|
JUnit4Assertions.assertEquals(expectedDTS, gotDTS) {
|
||||||
"Mismatched d.ts for module ${info.moduleName} at step $stepId"
|
"Mismatched d.ts for module ${info.moduleName} at step $stepId"
|
||||||
}
|
}
|
||||||
@@ -320,7 +319,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
val (jsOutput, rebuiltModules) = jsExecutableProducer.buildExecutable(multiModule = true, outJsProgram = true)
|
val (jsOutput, rebuiltModules) = jsExecutableProducer.buildExecutable(multiModule = true, outJsProgram = true)
|
||||||
verifyJsExecutableProducerBuildModules(projStep.id, rebuiltModules, projStep.dirtyJS)
|
verifyJsExecutableProducerBuildModules(projStep.id, rebuiltModules, projStep.dirtyJS)
|
||||||
verifyJsCode(projStep.id, mainModuleName, jsOutput)
|
verifyJsCode(projStep.id, mainModuleName, jsOutput)
|
||||||
verifyDTS(projStep.id, testInfo, jsOutput)
|
verifyDTS(projStep.id, testInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
||||||
@@ -36,6 +37,7 @@ import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
|
|||||||
import org.jetbrains.kotlin.test.model.*
|
import org.jetbrains.kotlin.test.model.*
|
||||||
import org.jetbrains.kotlin.test.services.*
|
import org.jetbrains.kotlin.test.services.*
|
||||||
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
||||||
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -256,17 +258,28 @@ class JsIrBackendFacade(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun File.fixJsFile(newJsTarget: File, moduleId: String, moduleKind: ModuleKind) {
|
||||||
|
val newJsCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(readText(), moduleKind, moduleId)
|
||||||
|
|
||||||
|
val oldJsMap = File("$absolutePath.map")
|
||||||
|
val jsCodeMap = (moduleKind == ModuleKind.PLAIN && oldJsMap.exists()).ifTrue { oldJsMap.readText() }
|
||||||
|
|
||||||
|
this.delete()
|
||||||
|
oldJsMap.delete()
|
||||||
|
|
||||||
|
newJsTarget.write(newJsCode)
|
||||||
|
jsCodeMap?.let { File("${newJsTarget.absolutePath}.map").write(it) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun CompilationOutputs.writeTo(outputFile: File, moduleId: String, moduleKind: ModuleKind) {
|
private fun CompilationOutputs.writeTo(outputFile: File, moduleId: String, moduleKind: ModuleKind) {
|
||||||
val wrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind)
|
val allJsFiles = writeAll(outputFile.parentFile, outputFile.nameWithoutExtension, false, moduleId, moduleKind)
|
||||||
outputFile.write(wrappedCode)
|
|
||||||
|
|
||||||
if (moduleKind == ModuleKind.PLAIN) {
|
val mainModuleFile = File(allJsFiles.last())
|
||||||
writeSourceMapIfPresent(outputFile)
|
mainModuleFile.fixJsFile(outputFile, moduleId, moduleKind)
|
||||||
}
|
|
||||||
|
|
||||||
dependencies.forEach { (moduleId, outputs) ->
|
dependencies.map { it.first }.zip(allJsFiles.dropLast(1)).forEach { (depModuleId, builtJsFilePath) ->
|
||||||
val moduleWrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(outputs.jsCode, moduleKind, moduleId)
|
val newFile = outputFile.augmentWithModuleName(depModuleId)
|
||||||
outputFile.augmentWithModuleName(moduleId).write(moduleWrappedCode)
|
File(builtJsFilePath).fixJsFile(newFile, depModuleId, moduleKind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.handlers
|
package org.jetbrains.kotlin.js.test.handlers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.backend.js.*
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
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.CacheUpdater
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer
|
import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
@@ -168,19 +169,10 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
|
|||||||
buildBinaryNoIC(configuration, mainModuleKlibFile, allDependencies)
|
buildBinaryNoIC(configuration, mainModuleKlibFile, allDependencies)
|
||||||
|
|
||||||
val binariesDir = File(buildDir, BIN_DIR_NAME).also { it.mkdirs() }
|
val binariesDir = File(buildDir, BIN_DIR_NAME).also { it.mkdirs() }
|
||||||
val binaries = ArrayList<File>(allDependencies.regularDependencies.size)
|
val binaries = compilationOutputs.writeAll(binariesDir, MAIN_MODULE_NAME, false, MAIN_MODULE_NAME, ModuleKind.PLAIN).map {
|
||||||
|
File(it)
|
||||||
for ((name, code) in compilationOutputs.dependencies) {
|
|
||||||
val depBinary = binariesDir.binJsFile(name)
|
|
||||||
depBinary.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
|
||||||
depBinary.writeText(code.jsCode)
|
|
||||||
binaries.add(depBinary)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val mainBinary = binariesDir.binJsFile(MAIN_MODULE_NAME)
|
|
||||||
mainBinary.writeText(compilationOutputs.jsCode)
|
|
||||||
binaries.add(mainBinary)
|
|
||||||
|
|
||||||
executeAndCheckBinaries(MAIN_MODULE_NAME, binaries)
|
executeAndCheckBinaries(MAIN_MODULE_NAME, binaries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user