[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:
Alexander Korepanov
2022-12-20 15:41:27 +01:00
committed by Space Team
parent dd268d67ff
commit 75931fb9c8
10 changed files with 163 additions and 118 deletions
@@ -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.SourceMapsInfo
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.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
@@ -225,16 +226,6 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
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> {
jsDir.invalidateDir()
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) {
val files = prepareExternalJsFiles()
jsOutput.dependencies.mapTo(files) { writeJsFile(it.first, it.second.jsCode) }
files += writeJsFile(mainModuleName, jsOutput.jsCode)
val compiledJsFiles = jsOutput.writeAll(jsDir, mainModuleName, true, mainModuleName, JS_MODULE_KIND)
for (jsCodeFile in compiledJsFiles) {
val jsFile = File(jsCodeFile)
jsFile.writeAsJsModule(jsFile.readText(), "./${jsFile.name}")
}
try {
V8IrJsTestChecker.checkWithTestFunctionArgs(
files = files,
files = files + compiledJsFiles,
testModuleName = "./$mainModuleName.js",
testPackageName = null,
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) {
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) {
"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)
verifyJsExecutableProducerBuildModules(projStep.id, rebuiltModules, projStep.dirtyJS)
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.transformers.irToJs.IrModuleToJsTransformer
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.declarations.IrModuleFragment
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.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
import java.io.File
@@ -256,17 +258,28 @@ class JsIrBackendFacade(
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) {
val wrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind)
outputFile.write(wrappedCode)
val allJsFiles = writeAll(outputFile.parentFile, outputFile.nameWithoutExtension, false, moduleId, moduleKind)
if (moduleKind == ModuleKind.PLAIN) {
writeSourceMapIfPresent(outputFile)
}
val mainModuleFile = File(allJsFiles.last())
mainModuleFile.fixJsFile(outputFile, moduleId, moduleKind)
dependencies.forEach { (moduleId, outputs) ->
val moduleWrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(outputs.jsCode, moduleKind, moduleId)
outputFile.augmentWithModuleName(moduleId).write(moduleWrappedCode)
dependencies.map { it.first }.zip(allJsFiles.dropLast(1)).forEach { (depModuleId, builtJsFilePath) ->
val newFile = outputFile.augmentWithModuleName(depModuleId)
File(builtJsFilePath).fixJsFile(newFile, depModuleId, moduleKind)
}
}
@@ -5,7 +5,7 @@
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.safeModuleName
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.ic.CacheUpdater
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.TranslationMode
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
@@ -168,19 +169,10 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
buildBinaryNoIC(configuration, mainModuleKlibFile, allDependencies)
val binariesDir = File(buildDir, BIN_DIR_NAME).also { it.mkdirs() }
val binaries = ArrayList<File>(allDependencies.regularDependencies.size)
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 binaries = compilationOutputs.writeAll(binariesDir, MAIN_MODULE_NAME, false, MAIN_MODULE_NAME, ModuleKind.PLAIN).map {
File(it)
}
val mainBinary = binariesDir.binJsFile(MAIN_MODULE_NAME)
mainBinary.writeText(compilationOutputs.jsCode)
binaries.add(mainBinary)
executeAndCheckBinaries(MAIN_MODULE_NAME, binaries)
}