Moved to IrReturnableBlock version with proper IrFile instead of String file name.

This commit is contained in:
Alexander Gorshenev
2019-02-01 17:12:59 +03:00
committed by Vasily Levchenko
parent 72af75f3a2
commit 67d6d47e5f
9 changed files with 105 additions and 57 deletions
@@ -9,24 +9,49 @@ import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.SourceRangeInfo
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrTerminalDeclarationReferenceBase
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.name.FqName
val File.lineStartOffsets: IntArray get() {
// TODO: could be incorrect, if file is not in system's line terminator format.
// Maybe use (0..document.lineCount - 1)
// .map { document.getLineStartOffset(it) }
// .toIntArray()
// as in PSI.
val separatorLength = System.lineSeparator().length
val buffer = mutableListOf<Int>()
var currentOffset = 0
this.forEachLine { line ->
buffer.add(currentOffset)
currentOffset += line.length + separatorLength
}
buffer.add(currentOffset)
return buffer.toIntArray()
}
val FileEntry.lineStartOffsets get() = File(name).let {
if (it.exists && it.isFile) it.lineStartOffsets else IntArray(0)
}
//-----------------------------------------------------------------------------//
/**
* TODO
@@ -37,33 +62,7 @@ import org.jetbrains.kotlin.name.FqName
* compilation stage (perhaps in or before inline face)
*/
class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.FileEntry {
private val lineStartOffsets: IntArray
//-------------------------------------------------------------------------//
init {
val file = File(name)
if (file.isFile) {
// TODO: could be incorrect, if file is not in system's line terminator format.
// Maybe use (0..document.lineCount - 1)
// .map { document.getLineStartOffset(it) }
// .toIntArray()
// as in PSI.
val separatorLength = System.lineSeparator().length
val buffer = mutableListOf<Int>()
var currentOffset = 0
file.forEachLine { line ->
buffer.add(currentOffset)
currentOffset += line.length + separatorLength
}
buffer.add(currentOffset)
lineStartOffsets = buffer.toIntArray()
} else {
lineStartOffsets = IntArray(0)
}
}
class NaiveSourceBasedFileEntryImpl(override val name: String, val lineStartOffsets: IntArray = IntArray(0)) : SourceManager.FileEntry {
//-------------------------------------------------------------------------//
@@ -216,4 +215,49 @@ internal class IrPrivateClassReferenceImpl(startOffset: Int,
{
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitClassReference(this, data)
}
class KonanIrReturnableBlockImpl(
startOffset: Int,
endOffset: Int,
type: IrType,
override val symbol: IrReturnableBlockSymbol,
origin: IrStatementOrigin? = null,
val sourceFile: IrFile? = null
) :
IrContainerExpressionBase(startOffset, endOffset, type, origin),
IrReturnableBlock {
override val descriptor = symbol.descriptor
constructor(
startOffset: Int,
endOffset: Int,
type: IrType,
symbol: IrReturnableBlockSymbol,
origin: IrStatementOrigin?,
statements: List<IrStatement>,
sourceFile: IrFile? = null
) : this(startOffset, endOffset, type, symbol, origin, sourceFile) {
this.statements.addAll(statements)
}
override val sourceFileName: String = sourceFile?.fileEntry?.name ?: "no source file"
init {
symbol.bind(this)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitBlock(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
statements.forEach { it.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
statements.forEachIndexed { i, irStatement ->
statements[i] = irStatement.transform(transformer, data)
}
}
}
@@ -193,11 +193,11 @@ val IrDeclaration.isSetter get() = this is IrSimpleFunction && this == this.corr
val IrDeclaration.isAccessor get() = this.isGetter || this.isSetter
val IrDeclaration.fileEntry: SourceManager.FileEntry get() = parent.let {
val IrDeclaration.file: IrFile get() = parent.let {
when (it) {
is IrFile -> it.fileEntry
is IrFile -> it
is IrPackageFragment -> TODO("Unknown file")
is IrDeclaration -> it.fileEntry
is IrDeclaration -> it.file
else -> TODO("Unexpected declaration parent")
}
}
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
@@ -857,7 +856,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrWhen -> return evaluateWhen (value)
is IrThrow -> return evaluateThrow (value)
is IrTry -> return evaluateTry (value)
is IrReturnableBlockImpl -> return evaluateReturnableBlock (value)
is IrReturnableBlock -> return evaluateReturnableBlock (value)
is IrContainerExpression -> return evaluateContainerExpression (value)
is IrWhileLoop -> return evaluateWhileLoop (value)
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
@@ -1661,14 +1660,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
//-------------------------------------------------------------------------//
fun getFileEntry(sourceFileName: String): SourceManager.FileEntry =
// We must cache file entries, otherwise we reparse same file many times.
context.fileEntryCache.getOrPut(sourceFileName) {
NaiveSourceBasedFileEntryImpl(sourceFileName)
}
val dummyFile = IrFileImpl(NaiveSourceBasedFileEntryImpl("no source file"))
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock) :
FileScope(IrFileImpl(getFileEntry(returnableBlock.sourceFileName))) {
FileScope((returnableBlock as? KonanIrReturnableBlockImpl)?.sourceFile ?: dummyFile) {
var bbExit : LLVMBasicBlockRef? = null
var resultPhi : LLVMValueRef? = null
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ir.KonanIrReturnableBlockImpl
import org.jetbrains.kotlin.backend.konan.irasdescriptors.file
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -93,7 +95,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
}
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
if (expression !is IrReturnableBlockImpl)
if (expression !is IrReturnableBlock)
return super.visitContainerExpression(expression)
using(ReturnableScope(expression.symbol)) {
@@ -292,7 +294,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
private inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol,
type: IrType, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null,
KonanIrReturnableBlockImpl(startOffset, endOffset, type, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, type)
.block(body).statements)
}
@@ -17,8 +17,9 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.backend.konan.ir.KonanIrReturnableBlockImpl
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fileEntry
import org.jetbrains.kotlin.backend.konan.irasdescriptors.file
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isInlineParameter
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
@@ -118,7 +118,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
}
}
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
private fun inlineFunction(callSite: IrCall, callee: IrFunction): KonanIrReturnableBlockImpl {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
@@ -149,7 +149,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
}
}
val sourceFileName = callee.fileEntry.name
val sourceFile = callee.file
val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) }
@@ -158,14 +158,14 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val isCoroutineIntrinsicCall = callSite.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(
context.config.configuration.languageVersionSettings)
return IrReturnableBlockImpl(
return KonanIrReturnableBlockImpl(
startOffset = startOffset,
endOffset = endOffset,
type = callSite.type,
symbol = irReturnableBlockSymbol,
origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
statements = statements,
sourceFileName = sourceFileName
sourceFile = sourceFile
).apply {
transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateClassReferenceImpl
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateFunctionCall
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateFunctionCallImpl
import org.jetbrains.kotlin.backend.konan.ir.KonanIrReturnableBlockImpl
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getErasedTypeClass
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.IrElement
@@ -1374,6 +1375,7 @@ internal object Devirtualization {
}
return when (expression) {
is IrReturnableBlock -> {
check(expression is KonanIrReturnableBlockImpl) // TODO: need to obtain IrFile rather than just sourceFileName
val foldedReturnableBlockValues = returnableBlockValues[expression]!!.associate {
it to fold(it, coercion, cast, false)
}
@@ -1385,14 +1387,14 @@ internal object Devirtualization {
val oldSymbol = expression.symbol
val newSymbol = IrReturnableBlockSymbolImpl(expression.descriptor)
val transformedReturnableBlock = with(expression) {
IrReturnableBlockImpl(
KonanIrReturnableBlockImpl(
startOffset = startOffset,
endOffset = endOffset,
type = coercion.type,
symbol = newSymbol,
origin = origin,
statements = statements,
sourceFileName = sourceFileName)
sourceFile = sourceFile)
}
transformedReturnableBlock.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitExpression(expression: IrExpression): IrExpression {
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.descriptors.findTopLevelDeclaration
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.descriptors.isSerializableExpectClass
import org.jetbrains.kotlin.backend.konan.ir.lineStartOffsets
import org.jetbrains.kotlin.backend.konan.library.SerializedIr
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ClassKind.*
@@ -1046,6 +1047,7 @@ internal class IrModuleSerializer(
fun serializeFileEntry(entry: SourceManager.FileEntry) = KonanIr.FileEntry.newBuilder()
.setName(serializeString(entry.name))
.addAllLineStartOffsets(entry.lineStartOffsets.asIterable())
.build()
val topLevelDeclarations = mutableMapOf<UniqId, ByteArray>()
@@ -1053,7 +1055,7 @@ internal class IrModuleSerializer(
fun serializeIrFile(file: IrFile): KonanIr.IrFile {
val proto = KonanIr.IrFile.newBuilder()
.setFileEntry(serializeFileEntry(file.fileEntry))
.setFqName(file.fqName.toString())
.setFqName(serializeString(file.fqName.toString()))
file.declarations.forEach {
if (it is IrTypeAlias) return@forEach
@@ -80,15 +80,15 @@ message IrDeclarationContainer {
repeated IrDeclaration declaration = 1;
}
message FileEntry { // TODO: extend me.
message FileEntry {
required String name = 1;
repeated int32 line_start_offsets = 2;
}
message IrFile {
repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2;
// TODO: we need a better string management. See metadata serialization as an example.
required string fq_name = 3;
required String fq_name = 3;
}
message IrModule {
@@ -310,10 +310,13 @@ class KonanIrModuleDeserializer(
}
fun deserializeIrFile(fileProto: KonanIr.IrFile, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(deserializeString(fileProto.fileEntry.name))
val fileEntry = NaiveSourceBasedFileEntryImpl(
deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = if (fileProto.fqName == "<root>") FqName.ROOT else FqName(fileProto.fqName)
val fqName = deserializeString(fileProto.fqName).let { if (it == "<root>") FqName.ROOT else FqName(it) }
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)