From c224dd4cb1281bcb75b2f921b08e3c7080909b0d Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Fri, 2 Apr 2021 17:16:12 +0300 Subject: [PATCH] JS IR: JsMapping serialization --- .../kotlin/backend/common/Mappings.kt | 31 ++- .../kotlin/ir/backend/js/JsMapping.kt | 217 +++++++++++++++--- 2 files changed, 202 insertions(+), 46 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Mappings.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Mappings.kt index eae0583d05f..3718dac85ab 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Mappings.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Mappings.kt @@ -36,18 +36,18 @@ interface Mapping { } } -open class DefaultMapping : Mapping { +interface DelegateFactory { + fun newDeclarationToDeclarationMapping(): Mapping.Delegate - override val defaultArgumentsDispatchFunction: Mapping.Delegate = newMapping() - override val defaultArgumentsOriginalFunction: Mapping.Delegate = newMapping() - override val suspendFunctionToCoroutineConstructor: Mapping.Delegate = newMapping() - override val lateInitFieldToNullableField: Mapping.Delegate = newMapping() - override val inlineClassMemberToStatic: Mapping.Delegate = newMapping() - override val capturedFields: Mapping.Delegate> = newMapping() - override val capturedConstructors: Mapping.Delegate = newMapping() - override val reflectedNameAccessor: Mapping.Delegate = newMapping() + fun > newDeclarationToDeclarationCollectionMapping(): Mapping.Delegate +} - protected open fun newMapping() = object : Mapping.Delegate() { +private object DefaultDelegateFactory : DelegateFactory { + override fun newDeclarationToDeclarationMapping(): Mapping.Delegate = newMappingImpl() + + override fun > newDeclarationToDeclarationCollectionMapping(): Mapping.Delegate = newMappingImpl() + + private fun newMappingImpl() = object : Mapping.Delegate() { private val map: MutableMap = ConcurrentHashMap() override operator fun get(key: K): V? { @@ -70,6 +70,17 @@ open class DefaultMapping : Mapping { } } +open class DefaultMapping(delegateFactory: DelegateFactory = DefaultDelegateFactory) : Mapping { + override val defaultArgumentsDispatchFunction: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() + override val defaultArgumentsOriginalFunction: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() + override val suspendFunctionToCoroutineConstructor: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() + override val lateInitFieldToNullableField: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() + override val inlineClassMemberToStatic: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() + override val capturedFields: Mapping.Delegate> = delegateFactory.newDeclarationToDeclarationCollectionMapping() + override val capturedConstructors: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() + override val reflectedNameAccessor: Mapping.Delegate = delegateFactory.newDeclarationToDeclarationMapping() +} + fun KMutableProperty0.getOrPut(fn: () -> V) = this.get() ?: fn().also { this.set(it) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt index 4345f89156a..9e5eceeec15 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt @@ -6,52 +6,197 @@ package org.jetbrains.kotlin.ir.backend.js import org.jetbrains.kotlin.backend.common.DefaultMapping +import org.jetbrains.kotlin.backend.common.DelegateFactory import org.jetbrains.kotlin.backend.common.Mapping import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.library.impl.* -class JsMapping(private val irFactory: IrFactory) : DefaultMapping() { - val outerThisFieldSymbols = newMapping() - val innerClassConstructors = newMapping() - val originalInnerClassPrimaryConstructorByClass = newMapping() - val secondaryConstructorToDelegate = newMapping() - val secondaryConstructorToFactory = newMapping() - val objectToGetInstanceFunction = newMapping() - val objectToInstanceField = newMapping() - val classToSyntheticPrimaryConstructor = newMapping() - val privateMemberToCorrespondingStatic = newMapping() +fun JsMapping(irFactory: IrFactory) = JsMapping(JsMappingState(irFactory)) - val constructorToInitFunction = newMapping() +class JsMapping(val state: JsMappingState) : DefaultMapping(state) { + val outerThisFieldSymbols = state.newDeclarationToDeclarationMapping() + val innerClassConstructors = state.newDeclarationToDeclarationMapping() + val originalInnerClassPrimaryConstructorByClass = state.newDeclarationToDeclarationMapping() + val secondaryConstructorToDelegate = state.newDeclarationToDeclarationMapping() + val secondaryConstructorToFactory = state.newDeclarationToDeclarationMapping() + val objectToGetInstanceFunction = state.newDeclarationToDeclarationMapping() + val objectToInstanceField = state.newDeclarationToDeclarationMapping() + val classToSyntheticPrimaryConstructor = state.newDeclarationToDeclarationMapping() + val privateMemberToCorrespondingStatic = state.newDeclarationToDeclarationMapping() - val enumEntryToGetInstanceFun = newMapping() - val enumEntryToInstanceField = newMapping() - val enumConstructorToNewConstructor = newMapping() - val enumClassToCorrespondingEnumEntry = newMapping() - val enumConstructorOldToNewValueParameters = newMapping() - val enumEntryToCorrespondingField = newMapping() - val enumClassToInitEntryInstancesFun = newMapping() + val constructorToInitFunction = state.newDeclarationToDeclarationMapping() - // Triggers `StageController.lazyLower` on access - override fun newMapping(): Mapping.Delegate = object : Mapping.Delegate() { - private val map: MutableMap = mutableMapOf() + val enumEntryToGetInstanceFun = state.newDeclarationToDeclarationMapping() + val enumEntryToInstanceField = state.newDeclarationToDeclarationMapping() + val enumConstructorToNewConstructor = state.newDeclarationToDeclarationMapping() + val enumClassToCorrespondingEnumEntry = state.newDeclarationToDeclarationMapping() + val enumConstructorOldToNewValueParameters = state.newDeclarationToDeclarationMapping() + val enumEntryToCorrespondingField = state.newDeclarationToDeclarationMapping() + val enumClassToInitEntryInstancesFun = state.newDeclarationToDeclarationMapping() +} - override operator fun get(key: K): V? { - irFactory.stageController.lazyLower(key) - return map[key] + +class JsMappingState(val irFactory: IrFactory) : DelegateFactory { + override fun newDeclarationToDeclarationMapping(): Mapping.Delegate { + return JsMappingDelegate(irFactory).also { + allMappings += it + } + } + + override fun > newDeclarationToDeclarationCollectionMapping(): Mapping.Delegate { + return JsMappingCollectionDelegate(irFactory).also { + allMappings += it + } + } + + private val allMappings = mutableListOf() + + fun serializeMappings(declarations: Iterable, symbolSerializer: (IrSymbol) -> Long): SerializedMappings { + return SerializedMappings(allMappings.map { mapping -> + val keys = mutableListOf() + val values = mutableListOf() + declarations.forEach { d -> + mapping.serializeMapping(d, symbolSerializer)?.let { bytes -> + keys += symbolSerializer((d as IrSymbolOwner).symbol) + values += bytes + } + } + + SerializedMapping( + IrMemoryLongArrayWriter(keys).writeIntoMemory(), + IrMemoryArrayWriter(values).writeIntoMemory(), + ) + }) + } + + fun mappingsDeserializer(mapping: SerializedMappings, signatureDeserializer: (Long) -> IdSignature, symbolDeserializer: (Long) -> IrSymbol): (IdSignature, IrDeclaration) -> Unit { + if (allMappings.size != mapping.mappings.size) error("Mapping size mismatch") + + val index = Array>(allMappings.size) { i -> + val bytes = mapping.mappings[i] + val s = IrLongArrayMemoryReader(bytes.keys).array.map(signatureDeserializer) + val v = IrArrayMemoryReader(bytes.values).toArray() + + if (s.size != v.size) error("Keys size != values size") + + s.withIndex().associate { it.value to v[it.index] } } - override operator fun set(key: K, value: V?) { - irFactory.stageController.lazyLower(key) - if (value == null) { - map.remove(key) - } else { - map[key] = value + return { signature, declaration -> + for (i in allMappings.indices) { + index[i][signature]?.let { bytes -> + allMappings[i].loadMapping(declaration, bytes, symbolDeserializer) + } } } - - override val keys: Set - get() = map.keys - - override val values: Collection - get() = map.values } } + +class SerializedMappings( + val mappings: List +) + +class SerializedMapping( + val keys: ByteArray, + val values: ByteArray, +) + +private interface SerializableMapping { + fun serializeMapping(declaration: IrDeclaration, symbolSerializer: (IrSymbol) -> Long): ByteArray? + + fun loadMapping(declaration: IrDeclaration, mapping: ByteArray, symbolDeserializer: (Long) -> IrSymbol) +} + +private class JsMappingDelegate(val irFactory: IrFactory) : Mapping.Delegate(), SerializableMapping { + + private val map: MutableMap = mutableMapOf() + + @Suppress("UNCHECKED_CAST") + override operator fun get(key: K): V? { + irFactory.stageController.lazyLower(key) + return map[(key as IrSymbolOwner).symbol]?.owner as? V + } + + override operator fun set(key: K, value: V?) { + irFactory.stageController.lazyLower(key) + if (value == null) { + map.remove((key as IrSymbolOwner).symbol) + } else { + map[(key as IrSymbolOwner).symbol] = (value as IrSymbolOwner).symbol + } + } + + override fun serializeMapping(declaration: IrDeclaration, symbolSerializer: (IrSymbol) -> Long): ByteArray? { + return map[(declaration as IrSymbolOwner).symbol]?.let { symbol -> + symbolSerializer(symbol).toByteArray() + } + } + + override fun loadMapping(declaration: IrDeclaration, mapping: ByteArray, symbolDeserializer: (Long) -> IrSymbol) { + map[(declaration as IrSymbolOwner).symbol] = symbolDeserializer(mapping.toLong()) + } + + override val keys: Set + get() = TODO("Not yet implemented") + + override val values: Collection + get() = TODO("Not yet implemented") +} + +private class JsMappingCollectionDelegate>(val irFactory: IrFactory) : Mapping.Delegate(), SerializableMapping { + private val map: MutableMap> = mutableMapOf() + + @Suppress("UNCHECKED_CAST") + override operator fun get(key: K): V? { + irFactory.stageController.lazyLower(key) + return map[(key as IrSymbolOwner).symbol]?.map { it.owner as IrDeclaration } as? V + } + + override operator fun set(key: K, value: V?) { + irFactory.stageController.lazyLower(key) + if (value == null) { + map.remove((key as IrSymbolOwner).symbol) + } else { + map[(key as IrSymbolOwner).symbol] = value.map { (it as IrSymbolOwner).symbol } + } + } + + override fun serializeMapping(declaration: IrDeclaration, symbolSerializer: (IrSymbol) -> Long): ByteArray? { + return map[(declaration as IrSymbolOwner).symbol]?.let { symbols -> + IrMemoryLongArrayWriter(symbols.map(symbolSerializer)).writeIntoMemory() + } + } + + override fun loadMapping(declaration: IrDeclaration, mapping: ByteArray, symbolDeserializer: (Long) -> IrSymbol) { + map[(declaration as IrSymbolOwner).symbol] = IrLongArrayMemoryReader(mapping).array.map(symbolDeserializer) + } + + override val keys: Set + get() = TODO("Not yet implemented") + + override val values: Collection + get() = TODO("Not yet implemented") +} + +fun ByteArray.toLong(): Long { + var result = this[0].toLong() and 0xFFL + for (i in 1..7) { + result = (result shl 8) or (this[i].toLong() and 0xFFL) + } + return result +} + +fun Long.toByteArray(): ByteArray { + val result = ByteArray(8) + + var self = this + + for (i in 7 downTo 0) { + result[i] = self.toByte() + self = self ushr 8 + } + + return result +} \ No newline at end of file