[JS IR] Support function type interfaces in incremental cache infrastructure
The patch removes logic of generating extra IrFiles (fake file) into IrModuleFragment for the function type interfaces during klib deserialization, because IC infrastructure can not process files which do not exist in klib. Instead of adding extra IrFiles during deserialization, the empty files with required packages are added into Kotlin/JS stdlib physically. These files are used as containers for function type interface declarations. Since Kotlin/WASM uses the same klib loading infrastructure as Kotlin/JS, the the empty files are added into Kotlin/WASM stdlib as well. The patch also adds a check that IrModuleFagment has files only from klib. ^KT-55720 Fixed
This commit is contained in:
committed by
Space Team
parent
1c3c5417ad
commit
9324cf3360
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.serialization.checkIsFunctionTypeInterfacePackageFqName
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
|
||||
class FunctionTypeInterfacePackages {
|
||||
companion object {
|
||||
private const val FUNCTION_TYPE_INTERFACE_DIR = "function-type-interface"
|
||||
}
|
||||
|
||||
private val functionTypeInterfacePackageFiles = hashSetOf<IrFile>()
|
||||
|
||||
// Function type interfaces are not declared in a standard library, and they are generated on flight during a klib deserialization.
|
||||
// The accessor allows finding a package for storing the generated function type interfaces.
|
||||
// The optimization reduces the size of a standard library klib.
|
||||
// Here are some numbers:
|
||||
// 255 interfaces in one package increase the size of uncompressed klib up to 3.5+MB;
|
||||
// 512 interfaces in one package increase the size of uncompressed klib up to 14.5+MB!
|
||||
// We need 3 packages.
|
||||
fun makePackageAccessor(stdlibModule: IrModuleFragment) = { packageFragmentDescriptor: PackageFragmentDescriptor ->
|
||||
val packageFqName = packageFragmentDescriptor.fqName.toString()
|
||||
check(checkIsFunctionTypeInterfacePackageFqName(packageFqName)) { "unexpected function type interface package $packageFqName" }
|
||||
|
||||
val fileWithRequiredPackage = "${packageFqName.replace('.', '-')}-package.kt"
|
||||
val packageFile = stdlibModule.files.singleOrNull {
|
||||
// Do not check by name "$FUNCTION_TYPE_INTERFACE_DIR/$fileWithRequiredPackage" because the path separator depends on OS
|
||||
it.fileEntry.name.endsWith(fileWithRequiredPackage) && it.fileEntry.name.contains(FUNCTION_TYPE_INTERFACE_DIR)
|
||||
} ?: error("can not find a functional interface file for $packageFqName package")
|
||||
|
||||
check(packageFragmentDescriptor.fqName == packageFile.fqName) {
|
||||
"unexpected package in file ${packageFile.fileEntry.name}; expected $packageFqName, got ${packageFile.fqName}"
|
||||
}
|
||||
|
||||
functionTypeInterfacePackageFiles += packageFile
|
||||
packageFile
|
||||
}
|
||||
|
||||
fun isFunctionTypeInterfacePackageFile(file: IrFile) = file in functionTypeInterfacePackageFiles
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
|
||||
@@ -38,7 +37,6 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrDescriptorBasedFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
@@ -71,6 +69,7 @@ import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.util.DummyLogger
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
||||
import java.io.File
|
||||
|
||||
val KotlinLibrary.moduleName: String
|
||||
@@ -184,14 +183,6 @@ fun deserializeDependencies(
|
||||
}
|
||||
}
|
||||
|
||||
fun getFunctionFactoryCallback(stdlibModule: IrModuleFragment) = { packageFragmentDescriptor: PackageFragmentDescriptor ->
|
||||
IrFileImpl(
|
||||
NaiveSourceBasedFileEntryImpl("${packageFragmentDescriptor.fqName}-[K][Suspend]Functions"),
|
||||
packageFragmentDescriptor,
|
||||
stdlibModule
|
||||
).also { stdlibModule.files += it }
|
||||
}
|
||||
|
||||
fun loadIr(
|
||||
depsDescriptors: ModulesStructure,
|
||||
irFactory: IrFactory,
|
||||
@@ -287,7 +278,9 @@ fun getIrModuleInfoForKlib(
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
typeTranslator,
|
||||
if (loadFunctionInterfacesIntoStdlib) getFunctionFactoryCallback(deserializedModuleFragments.first()) else null,
|
||||
loadFunctionInterfacesIntoStdlib.ifTrue {
|
||||
FunctionTypeInterfacePackages().makePackageAccessor(deserializedModuleFragments.first())
|
||||
},
|
||||
true
|
||||
)
|
||||
|
||||
@@ -345,7 +338,9 @@ fun getIrModuleInfoForSourceFiles(
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
psi2IrContext.typeTranslator,
|
||||
if (loadFunctionInterfacesIntoStdlib) getFunctionFactoryCallback(deserializedModuleFragments.first()) else null,
|
||||
loadFunctionInterfacesIntoStdlib.ifTrue {
|
||||
FunctionTypeInterfacePackages().makePackageAccessor(deserializedModuleFragments.first())
|
||||
},
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user