From ac2cf0eedb561e6cd8697e6e9a65a8544141337d Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Tue, 22 Jan 2019 14:21:20 +0300 Subject: [PATCH] Supported common lateinit lowering --- .../jetbrains/kotlin/backend/konan/Context.kt | 4 +- .../kotlin/backend/konan/KonanLower.kt | 1 - .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 24 ++- .../backend/konan/lower/FunctionInlining.kt | 2 +- .../backend/konan/lower/LateinitLowering.kt | 141 ------------------ .../kotlin/native/internal/RuntimeUtils.kt | 4 +- 6 files changed, 14 insertions(+), 162 deletions(-) delete mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 7cbd41d92cc..50a4b82e4d6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -339,8 +339,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { } fun printDescriptors() { - // A workaround to check if the lateinit field is assigned, see KT-9327 - try { moduleDescriptor } catch (e: UninitializedPropertyAccessException) { return } + if (!::moduleDescriptor.isInitialized) + return separator("Descriptors after: ${phase?.description}") moduleDescriptor.deepPrint() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 778136ebed4..feb004cc0aa 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.ExpectDeclarationsRemoving import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering -import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.ir.declarations.IrFile diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 6177e6acfe2..63ab5191381 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -125,13 +125,16 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir(context, lazySymbolTable) { - /** - * @note: - * [lateinitIsInitializedPropertyGetter] is used in [org.jetbrains.kotlin.backend.common.lower.LateinitLowering] and - * it's irrelevant for [org.jetbrains.kotlin.backend.konan.lower.LateinitLowering]. - */ + + private val isInitializedPropertyDescriptor = builtInsPackage("kotlin") + .getContributedVariables(Name.identifier("isInitialized"), NoLookupLocation.FROM_BACKEND).single { + it.extensionReceiverParameter.let { + it != null && TypeUtils.getClassDescriptor(it.type) == context.reflectionTypes.kProperty0 + } && !it.isExpect + } + override val lateinitIsInitializedPropertyGetter: IrSimpleFunctionSymbol - get() = TODO("unimplemented") + = symbolTable.referenceSimpleFunction(isInitializedPropertyDescriptor.getter!!) val entryPoint = findMainEntryPoint(context)?.let { symbolTable.referenceSimpleFunction(it) } @@ -450,15 +453,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val refClass = symbolTable.referenceClass(context.getInternalClass("Ref")) - val isInitializedPropertyDescriptor = builtInsPackage("kotlin") - .getContributedVariables(Name.identifier("isInitialized"), NoLookupLocation.FROM_BACKEND).single { - it.extensionReceiverParameter.let { - it != null && TypeUtils.getClassDescriptor(it.type) == context.reflectionTypes.kProperty0 - } && !it.isExpect - } - - val isInitializedGetter = symbolTable.referenceSimpleFunction(isInitializedPropertyDescriptor.getter!!) - val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl) val kMutableProperty0 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index 8331d29282f..7f328cde35b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -52,7 +52,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid val callSite = super.visitCall(expression) as IrCall if (!callSite.descriptor.needsInlining) return callSite - if (callSite.symbol == context.ir.symbols.isInitializedGetter) + if (callSite.symbol == context.ir.symbols.lateinitIsInitializedPropertyGetter) return callSite val callee = getFunctionDeclaration(callSite.symbol) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt deleted file mode 100644 index 5670ae31cb5..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan.lower - -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.lower.* -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride -import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal -import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrGetValue -import org.jetbrains.kotlin.ir.expressions.IrPropertyReference -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol -import org.jetbrains.kotlin.ir.util.dump -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.name.Name - -internal class LateinitLowering( - val context: Context, - private val generateParameterNameInAssertion: Boolean = false -) : FileLoweringPass { - - private val isInitializedGetter = context.ir.symbols.isInitializedGetter - - override fun lower(irFile: IrFile) { - irFile.transformChildrenVoid(object : IrBuildingTransformer(context) { - - override fun visitVariable(declaration: IrVariable): IrStatement { - declaration.transformChildrenVoid(this) - - if (!declaration.isLateinit) return declaration - - assert(declaration.initializer == null) { - "'lateinit' modifier is not allowed for variables with initializer" - } - builder.at(declaration).run { - declaration.initializer = irNull() - } - return declaration - } - - override fun visitGetValue(expression: IrGetValue): IrExpression { - val symbol = expression.symbol - if (symbol !is IrVariableSymbol || !symbol.owner.isLateinit) return expression - - builder.at(expression).run { - return irBlock(expression) { - // TODO: do data flow analysis to check if value is proved to be not-null. - +irIfThen( - irEqualsNull(irGet(expression.type, symbol)), - throwUninitializedPropertyAccessException(symbol.owner.name) - ) - +irGet(expression.type, symbol) - } - } - } - - override fun visitCall(expression: IrCall): IrExpression { - expression.transformChildrenVoid(this) - - if (expression.symbol != isInitializedGetter) return expression - - val propertyReference = expression.extensionReceiver!! as IrPropertyReference - assert(propertyReference.extensionReceiver == null) { - "'lateinit' modifier is not allowed on extension properties" - } - val getter = propertyReference.getter?.owner ?: TODO(propertyReference.dump()) - val property = getter.resolveFakeOverride().correspondingProperty!! - - builder.at(expression).run { - val field = property.backingField!! - val fieldValue = irGetField(propertyReference.dispatchReceiver, field) - return irNotEquals(fieldValue, irNull()) - } - } - - override fun visitProperty(declaration: IrProperty): IrStatement { - declaration.transformChildrenVoid(this) - - if (!declaration.isLateinit || !declaration.isReal) - return declaration - - val backingField = declaration.backingField!! - transformGetter(backingField, declaration.getter!!) - - assert(backingField.initializer == null) { - "'lateinit' modifier is not allowed for properties with initializer" - } - val irBuilder = context.createIrBuilder(backingField.symbol, declaration.startOffset, declaration.endOffset) - irBuilder.run { - backingField.initializer = irExprBody(irNull()) - } - - return declaration - } - - private fun transformGetter(backingField: IrField, getter: IrFunction) { - val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset) - irBuilder.run { - getter.body = irBlockBody { - val resultVar = irTemporary( - irGetField(getter.dispatchReceiverParameter?.let { irGet(it) }, backingField) - ) - +irIfThenElse( - context.irBuiltIns.nothingType, - irNotEquals(irGet(resultVar), irNull()), - irReturn(irGet(resultVar)), - throwUninitializedPropertyAccessException(backingField.name) - ) - } - } - } - }) - } - - private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(name: Name) = - irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply { - if (generateParameterNameInAssertion) { - putValueArgument( - 0, - IrConstImpl.string( - startOffset, - endOffset, - context.irBuiltIns.stringType, - name.asString() - ) - ) - } - } - - private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException - -} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt index ba6be49d0ad..fe508587f84 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt @@ -50,8 +50,8 @@ fun ThrowNoWhenBranchMatchedException(): Nothing { throw NoWhenBranchMatchedException() } -fun ThrowUninitializedPropertyAccessException(): Nothing { - throw UninitializedPropertyAccessException() +fun ThrowUninitializedPropertyAccessException(propertyName: String): Nothing { + throw UninitializedPropertyAccessException("lateinit property $propertyName has not been initialized") } @ExportForCppRuntime