Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.backend.common.phaser.performByIrFile.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2021 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.backend.common.phaser
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.ir.IrStatement
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.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapperPreservingSignatures
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
fun performByIrFile(
name: String = "PerformByIrFile",
description: String = "Perform phases by IrFile",
copyBeforeLowering: Boolean = true,
lower: List>,
): NamedCompilerPhase =
NamedCompilerPhase(
name, description, emptySet(), PerformByIrFilePhase(lower, copyBeforeLowering), emptySet(), emptySet(), emptySet(),
setOf(defaultDumper), nlevels = 1,
)
private class PerformByIrFilePhase(
private val lower: List>,
private val copyBeforeLowering: Boolean,
) : SameTypeCompilerPhase {
override fun invoke(
phaseConfig: PhaseConfig,
phaserState: PhaserState,
context: Context,
input: IrModuleFragment
): IrModuleFragment {
val nThreads = context.configuration.get(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS) ?: 1
return if (nThreads > 1)
invokeParallel(phaseConfig, phaserState, context, input, nThreads)
else
invokeSequential(phaseConfig, phaserState, context, input)
}
private fun invokeSequential(
phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment
): IrModuleFragment {
for (irFile in input.files) {
try {
val filePhaserState = phaserState.changeType()
for (phase in lower) {
phase.invoke(phaseConfig, filePhaserState, context, irFile)
}
} catch (e: Throwable) {
CodegenUtil.reportBackendException(e, "IR lowering", irFile.fileEntry.name)
}
}
// TODO: no guarantee that module identity is preserved by `lower`
return input
}
private fun invokeParallel(
phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment, nThreads: Int
): IrModuleFragment {
if (input.files.isEmpty()) return input
// We can only report one exception through ISE
val thrownFromThread = AtomicReference?>(null)
val remappedFiles = mutableMapOf()
val remappedFunctions = mutableMapOf()
val remappedClasses = mutableMapOf()
// Each thread needs its own copy of phaserState.alreadyDone
val filesAndStates = input.files.map {
if (copyBeforeLowering)
it.copySavingMappings(remappedFiles, remappedFunctions, remappedClasses) to phaserState.copyOf()
else
it to phaserState.copyOf()
}
val executor = Executors.newFixedThreadPool(nThreads)
for ((irFile, state) in filesAndStates) {
executor.execute {
try {
val filePhaserState = state.changeType()
for (phase in lower) {
phase.invoke(phaseConfig, filePhaserState, context, irFile)
}
} catch (e: Throwable) {
thrownFromThread.set(Pair(e, irFile))
}
}
}
executor.shutdown()
executor.awaitTermination(1, TimeUnit.DAYS) // Wait long enough
thrownFromThread.get()?.let { (e, irFile) ->
CodegenUtil.reportBackendException(e, "Experimental parallel IR backend", irFile.fileEntry.name)
}
// Presumably each thread has run through the same list of phases.
phaserState.alreadyDone.addAll(filesAndStates[0].second.alreadyDone)
// Repair after working on copied files.
if (copyBeforeLowering) {
input.files.clear()
input.files.addAll(filesAndStates.map { (irFile, _) -> irFile }.toMutableList())
// Some remappers in handleDeepCopy depend on entries in remappedFunctions inserted by adjustDefaultArgumentStubs.
adjustDefaultArgumentStubs(context, remappedFunctions)
context.handleDeepCopy(remappedFiles, remappedClasses, remappedFunctions)
// and some entries in adjustDefaultArgumentStubs depend on those inserted by handleDeepCopy, so we need to repeat the call.
adjustDefaultArgumentStubs(context, remappedFunctions)
input.transformChildrenVoid(CrossFileCallAdjuster(remappedFunctions))
}
// TODO: no guarantee that module identity is preserved by `lower`
return input
}
override fun getNamedSubphases(startDepth: Int): List>> =
lower.flatMap { it.getNamedSubphases(startDepth) }
}
// We need to remap inline function calls after lowering files
fun IrFile.copySavingMappings(
remappedFiles: MutableMap,
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)
}
remappedFiles[symbol] = newIrFile.symbol
return newIrFile
}
private class DeepCopySymbolRemapperSavingFunctions : DeepCopySymbolRemapperPreservingSignatures() {
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)
}
}
private 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 visitSimpleFunction(declaration: IrSimpleFunction): IrStatement {
declaration.overriddenSymbols = declaration.overriddenSymbols.map { remappedFunctions[it] ?: it }
return super.visitSimpleFunction(declaration)
}
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
}
}