From d154c8d8e67b9fbc49b2b888e36863c1cc4f3373 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Mon, 14 Dec 2020 20:15:41 +0300 Subject: [PATCH] IR: copy each file before lowering. Avoid inter-file dependencies while lowering. --- .../backend/common/CommonBackendContext.kt | 9 +- .../kotlin/backend/common/Mappings.kt | 9 ++ .../backend/common/phaser/CompilerPhase.kt | 4 +- .../backend/common/phaser/PhaseBuilders.kt | 95 ++++++++++++++++++- .../kotlin/ir/backend/js/JsMapping.kt | 6 ++ .../kotlin/backend/jvm/JvmBackendContext.kt | 19 ++++ .../kotlin/ir/util/DeepCopySavingMetadata.kt | 63 ++++++++++++ 7 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySavingMetadata.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt index 8ac18d2a9fe..29168b8309a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt @@ -13,7 +13,8 @@ import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irString import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol interface LoggingContext { var inVerbosePhase: Boolean @@ -36,4 +37,10 @@ interface CommonBackendContext : BackendContext, LoggingContext { } val mapping: Mapping + + // Adjust internal structures after a deep copy of some declarations. + fun handleDeepCopy( + classSymbolMap: MutableMap, + functionSymbolMap: MutableMap + ) {} } 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 96ec8335702..0823832b910 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 @@ -29,6 +29,9 @@ interface Mapping { operator fun setValue(thisRef: K, desc: KProperty<*>, value: V?) { set(thisRef, value) } + + abstract val keys: Set + abstract val values: Collection } } @@ -57,6 +60,12 @@ open class DefaultMapping : Mapping { map[key] = value } } + + override val keys: Set + get() = map.keys + + override val values: Collection + get() = map.values } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/CompilerPhase.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/CompilerPhase.kt index 4fe63a52b75..35676cdedec 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/CompilerPhase.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/CompilerPhase.kt @@ -13,7 +13,9 @@ class PhaserState( var depth: Int = 0, var phaseCount: Int = 0, val stickyPostconditions: MutableSet> = mutableSetOf() -) +) { + fun copyOf() = PhaserState(alreadyDone.toMutableSet(), depth, phaseCount, stickyPostconditions) +} // Copy state, forgetting the sticky postconditions (which will not be applicable to the new type) fun PhaserState.changeType() = PhaserState(alreadyDone, depth, phaseCount, mutableSetOf()) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt index a860fb8f1a8..5d5c3f73bab 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt @@ -13,6 +13,17 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper +import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom +import org.jetbrains.kotlin.ir.util.deepCopySavingMetadata +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import java.util.concurrent.Executors import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReference @@ -142,7 +153,7 @@ private class PerformByIrFilePhase( CodegenUtil.reportBackendException(e, "IR lowering", irFile.fileEntry.name) } } - + // TODO: no guarantee that module identity is preserved by `lower` return input } @@ -155,8 +166,13 @@ private class PerformByIrFilePhase( // We can only report one exception through ISE val thrownFromThread = AtomicReference?>(null) + val remappedFunctions = mutableMapOf() + val remappedClasses = mutableMapOf() + // Each thread needs its own copy of phaserState.alreadyDone - val filesAndStates = input.files.map { it to phaserState.clone() } + val filesAndStates = input.files.map { + it.copySavingMappings(remappedFunctions, remappedClasses) to phaserState.copyOf() + } val executor = Executors.newFixedThreadPool(nThreads) for ((irFile, state) in filesAndStates) { @@ -181,6 +197,13 @@ private class PerformByIrFilePhase( // Presumably each thread has run through the same list of phases. phaserState.alreadyDone.addAll(filesAndStates[0].second.alreadyDone) + input.files.clear() + input.files.addAll(filesAndStates.map { (irFile, _) -> irFile }.toMutableList()) + + adjustDefaultArgumentStubs(context, remappedFunctions) + input.transformChildrenVoid(CrossFileCallAdjuster(remappedFunctions)) + context.handleDeepCopy(remappedClasses, remappedFunctions) + // TODO: no guarantee that module identity is preserved by `lower` return input } @@ -256,3 +279,71 @@ fun transform(op: (OldData) - object : CompilerPhase { override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: OldData) = op(input) } + +// We need to remap inline function calls after lowering files + +fun IrFile.copySavingMappings( + remappedFunctions: MutableMap, + remappedClasses: MutableMap, +): IrFile { + val symbolRemapper = DeepCopySymbolRemapperSavingFunctions() + + val newIrFile = deepCopySavingMetadata(symbolRemapper = symbolRemapper) + + for (function in symbolRemapper.declaredFunctions) { + remappedFunctions[function] = symbolRemapper.getReferencedSimpleFunction(function) + } + for (klass in symbolRemapper.declaredClasses) { + remappedClasses[klass] = symbolRemapper.getReferencedClass(klass) + } + + return newIrFile +} + +private class DeepCopySymbolRemapperSavingFunctions : DeepCopySymbolRemapper() { + val declaredFunctions = mutableSetOf() + val declaredClasses = mutableSetOf() + + override fun getDeclaredFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol { + declaredFunctions.add(symbol) + return super.getDeclaredFunction(symbol) + } + + override fun getDeclaredClass(symbol: IrClassSymbol): IrClassSymbol { + declaredClasses.add(symbol) + return super.getDeclaredClass(symbol) + } +} + +fun adjustDefaultArgumentStubs( + context: CommonBackendContext, + remappedFunctions: MutableMap, +) { + for (defaultStub in context.mapping.defaultArgumentsOriginalFunction.keys) { + if (defaultStub !is IrSimpleFunction) continue + val original = context.mapping.defaultArgumentsOriginalFunction[defaultStub] as? IrSimpleFunction ?: continue + val originalNew = remappedFunctions[original.symbol]?.owner ?: continue + val defaultStubNew = context.mapping.defaultArgumentsDispatchFunction[originalNew] ?: continue + remappedFunctions[defaultStub.symbol] = defaultStubNew.symbol as IrSimpleFunctionSymbol + } +} + +private class CrossFileCallAdjuster( + val remappedFunctions: Map +) : IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + return remappedFunctions[expression.symbol]?.let { newSymbol -> + with(expression) { + IrCallImpl( + startOffset, endOffset, type, + newSymbol, + typeArgumentsCount, valueArgumentsCount, origin, + superQualifierSymbol // TODO + ).apply { + copyTypeAndValueArgumentsFrom(expression) + } + } + } ?: expression + } +} \ No newline at end of file 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 1879b045266..4345f89156a 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 @@ -47,5 +47,11 @@ class JsMapping(private val irFactory: IrFactory) : DefaultMapping() { map[key] = value } } + + override val keys: Set + get() = map.keys + + override val values: Collection + get() = map.values } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index c46c3929030..766bbe9965c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -154,6 +154,25 @@ class JvmBackendContext( +irThrow(irNull()) } + override fun handleDeepCopy( + classSymbolMap: MutableMap, + functionSymbolMap: MutableMap + ) { + val oldClassesWithNameOverride = classNameOverride.keys.toList() + for (klass in oldClassesWithNameOverride) { + classSymbolMap[klass.symbol]?.let { newSymbol -> + classNameOverride[newSymbol.owner] = classNameOverride[klass]!! + } + } + for (multifileFacade in multifileFacadesToAdd) { + val oldPartClasses = multifileFacade.value + val newPartClasses = oldPartClasses.map { classSymbolMap[it.symbol]?.owner ?: it } + multifileFacade.setValue(newPartClasses.toMutableList()) + } + + super.handleDeepCopy(classSymbolMap, functionSymbolMap) + } + inner class JvmIr( irModuleFragment: IrModuleFragment, symbolTable: SymbolTable diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySavingMetadata.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySavingMetadata.kt new file mode 100644 index 00000000000..8e0c641fba2 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySavingMetadata.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2020 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.util + +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.visitors.acceptVoid + +fun T.deepCopySavingMetadata( + initialParent: IrDeclarationParent? = null, + symbolRemapper: DeepCopySymbolRemapper = DeepCopySymbolRemapper() +): T { + acceptVoid(symbolRemapper) + val typeRemapper = DeepCopyTypeRemapper(symbolRemapper) + @Suppress("UNCHECKED_CAST") + return transform(DeepCopySavingMetadata(symbolRemapper, typeRemapper, SymbolRenamer.DEFAULT), null) + .patchDeclarationParents(initialParent) as T +} + +private class DeepCopySavingMetadata( + symbolRemapper: SymbolRemapper, + typeRemapper: TypeRemapper, + symbolRenamer: SymbolRenamer +) : DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper, symbolRenamer) { + override fun visitFile(declaration: IrFile): IrFile = + super.visitFile(declaration).apply { + metadata = declaration.metadata + } + + override fun visitClass(declaration: IrClass): IrClass = + super.visitClass(declaration).apply { + metadata = declaration.metadata + + } + + override fun visitConstructor(declaration: IrConstructor): IrConstructor = + super.visitConstructor(declaration).apply { + metadata = declaration.metadata + } + + override fun visitSimpleFunction(declaration: IrSimpleFunction): IrSimpleFunction = + super.visitSimpleFunction(declaration).apply { + metadata = declaration.metadata + } + + override fun visitProperty(declaration: IrProperty): IrProperty = + super.visitProperty(declaration).apply { + metadata = declaration.metadata + } + + override fun visitField(declaration: IrField): IrField = + super.visitField(declaration).apply { + metadata = declaration.metadata + } + + override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrLocalDelegatedProperty = + super.visitLocalDelegatedProperty(declaration).apply { + metadata = declaration.metadata + } +} \ No newline at end of file