[JS IR] Simple memory optimizations
- Use hash maps and hash sets instead of linked implementations - Use weak hash maps for caches with IR elements as keys - Intern JS function signatures
This commit is contained in:
committed by
Space Team
parent
731dd9c3e8
commit
95e305be3a
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceMapNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.WeakHashMap
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class JsIrBackendContext(
|
||||
@@ -73,9 +74,9 @@ class JsIrBackendContext(
|
||||
override val scriptMode: Boolean get() = false
|
||||
|
||||
val polyfills = JsPolyfills()
|
||||
val fieldToInitializer: MutableMap<IrField, IrExpression> = mutableMapOf()
|
||||
val fieldToInitializer = WeakHashMap<IrField, IrExpression>()
|
||||
|
||||
val localClassNames: MutableMap<IrClass, String> = mutableMapOf()
|
||||
val localClassNames = WeakHashMap<IrClass, String>()
|
||||
|
||||
val minimizedNameGenerator: MinimizedNameGenerator =
|
||||
MinimizedNameGenerator()
|
||||
@@ -83,7 +84,7 @@ class JsIrBackendContext(
|
||||
val keeper: Keeper =
|
||||
Keeper(keep)
|
||||
|
||||
val fieldDataCache = mutableMapOf<IrClass, Map<IrField, String>>()
|
||||
val fieldDataCache = WeakHashMap<IrClass, Map<IrField, String>>()
|
||||
|
||||
override val builtIns = module.builtIns
|
||||
|
||||
@@ -387,7 +388,7 @@ class JsIrBackendContext(
|
||||
print(message)
|
||||
}
|
||||
|
||||
private val outlinedJsCodeFunctions = mutableMapOf<IrFunctionSymbol, JsFunction>()
|
||||
private val outlinedJsCodeFunctions = WeakHashMap<IrFunctionSymbol, JsFunction>()
|
||||
|
||||
fun addOutlinedJsCode(symbol: IrSimpleFunctionSymbol, outlinedJsCode: JsFunction) {
|
||||
outlinedJsCodeFunctions[symbol] = outlinedJsCode
|
||||
|
||||
@@ -119,7 +119,7 @@ class CacheUpdater(
|
||||
) : KotlinSourceFileExports() {
|
||||
override fun getExportedSignatures(): Set<IdSignature> = allExportedSignatures
|
||||
|
||||
val allExportedSignatures = mutableSetOf<IdSignature>()
|
||||
val allExportedSignatures = hashSetOf<IdSignature>()
|
||||
}
|
||||
|
||||
private class DirtyFileMetadata(
|
||||
@@ -132,13 +132,13 @@ class CacheUpdater(
|
||||
) : KotlinSourceFileMetadata() {
|
||||
fun addInverseDependency(lib: KotlinLibraryFile, src: KotlinSourceFile, signature: IdSignature) =
|
||||
when (val signatures = inverseDependencies[lib, src]) {
|
||||
null -> inverseDependencies[lib, src] = mutableSetOf(signature)
|
||||
null -> inverseDependencies[lib, src] = hashSetOf(signature)
|
||||
else -> signatures += signature
|
||||
}
|
||||
|
||||
fun addDirectDependency(lib: KotlinLibraryFile, src: KotlinSourceFile, signature: IdSignature, hash: ICHash) =
|
||||
when (val signatures = directDependencies[lib, src]) {
|
||||
null -> directDependencies[lib, src] = mutableMapOf(signature to hash)
|
||||
null -> directDependencies[lib, src] = hashMapOf(signature to hash)
|
||||
else -> signatures[signature] = hash
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ class CacheUpdater(
|
||||
}
|
||||
|
||||
private fun loadModifiedFiles(): KotlinSourceFileMap<KotlinSourceFileMetadata> {
|
||||
val removedFilesMetadata = mutableMapOf<KotlinLibraryFile, Map<KotlinSourceFile, KotlinSourceFileMetadata>>()
|
||||
val removedFilesMetadata = hashMapOf<KotlinLibraryFile, Map<KotlinSourceFile, KotlinSourceFileMetadata>>()
|
||||
|
||||
val modifiedFiles = KotlinSourceFileMap(incrementalCaches.entries.associate { (lib, cache) ->
|
||||
val (dirtyFiles, removedFiles, newFiles, modifiedConfigFiles) = cache.collectModifiedFiles(configHash)
|
||||
@@ -228,7 +228,7 @@ class CacheUpdater(
|
||||
val exportedSymbols = KotlinSourceFileMutableMap<KotlinSourceFileExports>()
|
||||
|
||||
for ((libFile, srcFiles) in dirtyFiles) {
|
||||
val exportedSymbolFiles = mutableMapOf<KotlinSourceFile, KotlinSourceFileExports>()
|
||||
val exportedSymbolFiles = HashMap<KotlinSourceFile, KotlinSourceFileExports>(srcFiles.size)
|
||||
for ((srcFile, srcFileMetadata) in srcFiles) {
|
||||
val loadingFileExports = DirtyFileExports()
|
||||
for ((dependentLib, dependentFiles) in srcFileMetadata.inverseDependencies) {
|
||||
@@ -264,7 +264,7 @@ class CacheUpdater(
|
||||
}
|
||||
|
||||
private fun collectImplementedSymbol(deserializedSymbols: Map<IdSignature, IrSymbol>): Map<IdSignature, IrSymbol> {
|
||||
return buildMap(deserializedSymbols.size) {
|
||||
return HashMap<IdSignature, IrSymbol>(deserializedSymbols.size).apply {
|
||||
for ((signature, symbol) in deserializedSymbols) {
|
||||
put(signature, symbol)
|
||||
|
||||
@@ -351,7 +351,7 @@ class CacheUpdater(
|
||||
val incrementalCache = getLibIncrementalCache(libFile)
|
||||
for (fileDeserializer in moduleDeserializer.fileDeserializers()) {
|
||||
val reachableSignatures = fileDeserializer.symbolDeserializer.signatureDeserializer.signatureToIndexMapping()
|
||||
val maybeImportedSignatures = reachableSignatures.keys.toMutableSet()
|
||||
val maybeImportedSignatures = HashSet(reachableSignatures.keys)
|
||||
val implementedSymbols = collectImplementedSymbol(fileDeserializer.symbolDeserializer.deserializedSymbols)
|
||||
for ((signature, symbol) in implementedSymbols) {
|
||||
var symbolCanBeExported = maybeImportedSignatures.remove(signature)
|
||||
@@ -506,7 +506,7 @@ class CacheUpdater(
|
||||
|
||||
dependentSignatures.keys != newSignatures -> {
|
||||
val newMetadata = addNewMetadata(dependentLibFile, dependentSrcFile, dependentSrcMetadata)
|
||||
newMetadata.directDependencies[libFile, srcFile] = newSignatures.associateWith {
|
||||
newMetadata.directDependencies[libFile, srcFile] = newSignatures.associateWithTo(HashMap(newSignatures.size)) {
|
||||
signatureHashCalculator[it] ?: notFoundIcError("signature $it hash", libFile, srcFile)
|
||||
}
|
||||
}
|
||||
@@ -571,7 +571,7 @@ class CacheUpdater(
|
||||
fragmentToLibName[it.irFile.module] ?: notFoundIcError("loaded fragment lib name", srcFile = KotlinSourceFile(it.irFile))
|
||||
}
|
||||
|
||||
val visited = mutableSetOf<KotlinLibrary>()
|
||||
val visited = hashSetOf<KotlinLibrary>()
|
||||
val artifacts = mutableListOf<ModuleArtifact>()
|
||||
fun addArtifact(lib: KotlinLibrary) {
|
||||
if (visited.add(lib)) {
|
||||
|
||||
@@ -53,11 +53,11 @@ internal inline fun <E> buildListUntil(to: Int, builderAction: MutableList<E>.(I
|
||||
}
|
||||
|
||||
internal inline fun <E> buildSetUntil(to: Int, builderAction: MutableSet<E>.(Int) -> Unit): Set<E> {
|
||||
return buildSet(to) { repeat(to) { builderAction(it) } }
|
||||
return HashSet<E>(to).apply { repeat(to) { builderAction(it) } }
|
||||
}
|
||||
|
||||
internal inline fun <K, V> buildMapUntil(to: Int, builderAction: MutableMap<K, V>.(Int) -> Unit): Map<K, V> {
|
||||
return buildMap(to) { repeat(to) { builderAction(it) } }
|
||||
return HashMap<K, V>(to).apply { repeat(to) { builderAction(it) } }
|
||||
}
|
||||
|
||||
internal class StopwatchIC {
|
||||
|
||||
+5
-5
@@ -21,12 +21,12 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
|
||||
class IdSignatureHashCalculator {
|
||||
private val flatHashes = mutableMapOf<IrFunction, ICHash>()
|
||||
private val inlineFunctionCallGraph: MutableMap<IrFunction, Set<IrFunction>> = mutableMapOf()
|
||||
private val processingFunctions = mutableSetOf<IrFunction>()
|
||||
private val functionTransitiveHashes = mutableMapOf<IrFunction, ICHash>()
|
||||
private val flatHashes = hashMapOf<IrFunction, ICHash>()
|
||||
private val inlineFunctionCallGraph = hashMapOf<IrFunction, Set<IrFunction>>()
|
||||
private val processingFunctions = hashSetOf<IrFunction>()
|
||||
private val functionTransitiveHashes = hashMapOf<IrFunction, ICHash>()
|
||||
|
||||
private val allIdSignatureHashes = mutableMapOf<IdSignature, ICHash>()
|
||||
private val allIdSignatureHashes = hashMapOf<IdSignature, ICHash>()
|
||||
|
||||
|
||||
private inner class FlatHashCalculator : IrElementVisitorVoid {
|
||||
|
||||
+5
-5
@@ -25,7 +25,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
|
||||
private var forceRebuildJs = false
|
||||
private val cacheDir = File(cachePath)
|
||||
private val signatureToIndexMappingFromMetadata = mutableMapOf<KotlinSourceFile, MutableMap<IdSignature, Int>>()
|
||||
private val signatureToIndexMappingFromMetadata = hashMapOf<KotlinSourceFile, MutableMap<IdSignature, Int>>()
|
||||
|
||||
private val libraryFile = KotlinLibraryFile(library)
|
||||
|
||||
@@ -69,7 +69,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
override val directDependencies = KotlinSourceFileMap<Map<IdSignature, ICHash>>(emptyMap())
|
||||
}
|
||||
|
||||
private val kotlinLibrarySourceFileMetadata = mutableMapOf<KotlinSourceFile, KotlinSourceFileMetadata>()
|
||||
private val kotlinLibrarySourceFileMetadata = hashMapOf<KotlinSourceFile, KotlinSourceFileMetadata>()
|
||||
|
||||
private fun KotlinSourceFile.getCacheFile(suffix: String) = File(cacheDir, "${File(path).name}.${path.stringHashForIC()}.$suffix")
|
||||
|
||||
@@ -123,11 +123,11 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
}
|
||||
|
||||
val cachedFingerprints = loadCachedFingerprints()
|
||||
val deletedFiles = cachedFingerprints.keys.toMutableSet()
|
||||
val deletedFiles = HashSet(cachedFingerprints.keys)
|
||||
val unknownFiles = mutableSetOf<KotlinSourceFile>()
|
||||
|
||||
val newFingerprints = kotlinLibraryHeader.sourceFiles.mapIndexed { index, file -> file to library.fingerprint(index) }
|
||||
val modifiedFiles = buildMap(newFingerprints.size) {
|
||||
val modifiedFiles = HashMap<KotlinSourceFile, KotlinSourceFileMetadata>(newFingerprints.size).apply {
|
||||
for ((file, fileNewFingerprint) in newFingerprints) {
|
||||
val oldFingerprint = cachedFingerprints[file]
|
||||
if (oldFingerprint == null) {
|
||||
@@ -170,7 +170,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
|
||||
private fun fetchSourceFileMetadata(srcFile: KotlinSourceFile, loadSignatures: Boolean) =
|
||||
kotlinLibrarySourceFileMetadata.getOrPut(srcFile) {
|
||||
val signatureToIndexMapping = signatureToIndexMappingFromMetadata.getOrPut(srcFile) { mutableMapOf() }
|
||||
val signatureToIndexMapping = signatureToIndexMappingFromMetadata.getOrPut(srcFile) { hashMapOf() }
|
||||
val deserializer: IdSignatureDeserializer by lazy {
|
||||
kotlinLibraryHeader.signatureDeserializers[srcFile] ?: notFoundIcError("signature deserializer", libraryFile, srcFile)
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ internal class JsIrLinkerLoader(
|
||||
}
|
||||
|
||||
private fun loadModules(): Map<ModuleDescriptor, KotlinLibrary> {
|
||||
val descriptors = mutableMapOf<KotlinLibrary, ModuleDescriptorImpl>()
|
||||
val descriptors = hashMapOf<KotlinLibrary, ModuleDescriptorImpl>()
|
||||
var runtimeModule: ModuleDescriptorImpl? = null
|
||||
|
||||
// TODO: deduplicate this code using part from klib.kt
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ class JsMultiModuleCache(private val moduleArtifacts: List<ModuleArtifact>) {
|
||||
|
||||
class CachedModuleInfo(val artifact: ModuleArtifact, val jsIrHeader: JsIrModuleHeader, var crossModuleReferencesHash: ICHash = ICHash())
|
||||
|
||||
private val headerToCachedInfo = mutableMapOf<JsIrModuleHeader, CachedModuleInfo>()
|
||||
private val headerToCachedInfo = hashMapOf<JsIrModuleHeader, CachedModuleInfo>()
|
||||
|
||||
private fun ModuleArtifact.fetchModuleInfo() = File(artifactsDir, JS_MODULE_HEADER).useCodedInputIfExists {
|
||||
val definitions = mutableSetOf<String>()
|
||||
|
||||
+5
-5
@@ -53,17 +53,17 @@ open class KotlinSourceFileMap<out T>(files: Map<KotlinLibraryFile, Map<KotlinSo
|
||||
}
|
||||
|
||||
class KotlinSourceFileMutableMap<T>(
|
||||
private val files: MutableMap<KotlinLibraryFile, MutableMap<KotlinSourceFile, T>> = mutableMapOf()
|
||||
private val files: MutableMap<KotlinLibraryFile, MutableMap<KotlinSourceFile, T>> = hashMapOf()
|
||||
) : KotlinSourceFileMap<T>(files) {
|
||||
|
||||
operator fun set(libFile: KotlinLibraryFile, sourceFile: KotlinSourceFile, data: T) = getOrPutFiles(libFile).put(sourceFile, data)
|
||||
operator fun set(libFile: KotlinLibraryFile, sourceFiles: MutableMap<KotlinSourceFile, T>) = files.put(libFile, sourceFiles)
|
||||
|
||||
fun getOrPutFiles(libFile: KotlinLibraryFile) = files.getOrPut(libFile) { mutableMapOf() }
|
||||
fun getOrPutFiles(libFile: KotlinLibraryFile) = files.getOrPut(libFile) { hashMapOf() }
|
||||
|
||||
fun copyFilesFrom(other: KotlinSourceFileMap<T>) {
|
||||
for ((libFile, srcFiles) in other) {
|
||||
files.getOrPut(libFile) { mutableMapOf() } += srcFiles
|
||||
files.getOrPut(libFile) { hashMapOf() } += srcFiles
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +81,11 @@ class KotlinSourceFileMutableMap<T>(
|
||||
}
|
||||
|
||||
fun <T> KotlinSourceFileMap<T>.toMutable(): KotlinSourceFileMutableMap<T> {
|
||||
return KotlinSourceFileMutableMap(entries.associateTo(mutableMapOf()) { it.key to it.value.toMutableMap() })
|
||||
return KotlinSourceFileMutableMap(entries.associateTo(HashMap(entries.size)) { it.key to HashMap(it.value) })
|
||||
}
|
||||
|
||||
fun KotlinSourceFileMap<Set<IdSignature>>.flatSignatures(): Set<IdSignature> {
|
||||
val allSignatures = mutableSetOf<IdSignature>()
|
||||
val allSignatures = hashSetOf<IdSignature>()
|
||||
forEachFile { _, _, signatures -> allSignatures += signatures }
|
||||
return allSignatures
|
||||
}
|
||||
|
||||
+3
-3
@@ -106,7 +106,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
||||
|
||||
private fun IrClass.fieldData(): Map<IrField, String> {
|
||||
return context.fieldDataCache.getOrPut(this) {
|
||||
val nameCnt = mutableMapOf<String, Int>()
|
||||
val nameCnt = hashMapOf<String, Int>()
|
||||
|
||||
val allClasses = DFS.topologicalOrder(listOf(this)) { node ->
|
||||
node.superTypes.mapNotNull {
|
||||
@@ -114,7 +114,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
||||
}
|
||||
}
|
||||
|
||||
val result = mutableMapOf<IrField, String>()
|
||||
val result = hashMapOf<IrField, String>()
|
||||
|
||||
if (minimizedMemberNames) {
|
||||
allClasses.reversed().forEach {
|
||||
@@ -187,4 +187,4 @@ private fun List<JsName>.makeRef(): JsNameRef {
|
||||
result = JsNameRef(this[i], result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
class MinimizedNameGenerator {
|
||||
private var index = 0
|
||||
private val functionSignatureToName = mutableMapOf<String, String>()
|
||||
private val reservedNames = mutableSetOf<String>()
|
||||
private val keptNames = mutableSetOf<String>()
|
||||
private val functionSignatureToName = hashMapOf<String, String>()
|
||||
private val reservedNames = hashSetOf<String>()
|
||||
private val keptNames = hashSetOf<String>()
|
||||
|
||||
fun generateNextName(): String {
|
||||
var candidate = index++.toJsIdentifier()
|
||||
@@ -39,4 +39,4 @@ class MinimizedNameGenerator {
|
||||
functionSignatureToName.clear()
|
||||
reservedNames.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,13 +149,11 @@ fun calculateJsFunctionSignature(declaration: IrFunction, context: JsIrBackendCo
|
||||
}
|
||||
}
|
||||
|
||||
val signature = nameBuilder.toString()
|
||||
val signature = abs(nameBuilder.toString().hashCode()).toString(Character.MAX_RADIX)
|
||||
|
||||
// TODO: Use better hashCode
|
||||
return sanitizeName(
|
||||
declarationName,
|
||||
withHash = false
|
||||
) + "_" + abs(signature.hashCode()).toString(Character.MAX_RADIX) + RESERVED_MEMBER_NAME_SUFFIX
|
||||
val sanitizedName = sanitizeName(declarationName, withHash = false)
|
||||
return "${sanitizedName}_$signature$RESERVED_MEMBER_NAME_SUFFIX".intern()
|
||||
}
|
||||
|
||||
fun jsFunctionSignature(
|
||||
|
||||
+4
-3
@@ -13,14 +13,15 @@ import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.*
|
||||
|
||||
class IrFactoryImplForJsIC(override val stageController: StageController) : AbstractIrFactoryImpl(), IdSignatureRetriever {
|
||||
private val declarationToSignature = mutableMapOf<IrDeclaration, IdSignature>()
|
||||
private val declarationToSignature = WeakHashMap<IrDeclaration, IdSignature>()
|
||||
|
||||
private fun <T : IrDeclaration> T.register(): T {
|
||||
val parentSig = stageController.currentDeclaration?.let { declarationSignature(it) } ?: return this
|
||||
|
||||
stageController.createSignature(parentSig)?.let { declarationToSignature[this] = it}
|
||||
stageController.createSignature(parentSig)?.let { declarationToSignature[this] = it }
|
||||
|
||||
return this
|
||||
}
|
||||
@@ -392,4 +393,4 @@ class IrFactoryImplForJsIC(override val stageController: StageController) : Abst
|
||||
isAssignable,
|
||||
).register()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user