Implemented 'lateinit' properties

If property is lateinit, then on each access we need to test its value
and throw UninitializedPropertyAccessException if it is null.
This commit is contained in:
Igor Chevdar
2017-03-21 16:38:30 +03:00
parent e170edac17
commit 55d3b23cfe
5 changed files with 90 additions and 15 deletions
@@ -48,6 +48,9 @@ internal class KonanLower(val context: Context) {
DefaultArgumentStubGenerator(context).runOnFilePostfix(irFile)
DefaultParameterInjector(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_LATEINIT) {
LateinitLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_BUILTIN_OPERATORS) {
BuiltinOperatorLowering(context).runOnFilePostfix(irFile)
}
@@ -3,7 +3,7 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.util.*
enum class KonanPhase(val description: String,
val prerequisite: Set<KonanPhase> = setOf<KonanPhase>(),
vararg prerequisite: KonanPhase,
var enabled: Boolean = true, var verbose: Boolean = false) {
/* */ FRONTEND("Frontend builds AST"),
@@ -14,27 +14,29 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_INTEROP("Interop lowering"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", setOf(LOWER_ENUMS)),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", setOf(LOWER_INITIALIZERS)),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", setOf(
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION)),
/* ... ... */ LOWER_VARARG("Vararg lowering", setOf(LOWER_CALLABLES)),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", setOf(LOWER_SHARED_VARIABLES)),
/* ... ... */ LOWER_TAILREC("tailrec lowering", setOf(LOWER_LOCAL_FUNCTIONS)),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", setOf(
LOWER_TAILREC, LOWER_ENUMS)),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", setOf(LOWER_DEFAULT_PARAMETER_EXTENT)),
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", setOf(
LOWER_DEFAULT_PARAMETER_EXTENT)),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering",
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION),
/* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES),
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering",
LOWER_TAILREC, LOWER_ENUMS),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT),
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering"),
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", LOWER_DEFAULT_PARAMETER_EXTENT, LOWER_LATEINIT),
/* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering"),
/* ... ... */ BRIDGES_BUILDING("Bridges building"),
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
/* ... ... */ AUTOBOX("Autoboxing of primitive types", setOf(BRIDGES_BUILDING)),
/* ... ... */ AUTOBOX("Autoboxing of primitive types", BRIDGES_BUILDING),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ CODEGEN("Code Generation"),
/* ... ... */ METADATOR("Metadata Generation"),
/* */ LINKER("Link Stage")
/* */ LINKER("Link Stage");
val prerequisite = prerequisite.toSet()
}
object KonanPhases {
@@ -0,0 +1,57 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
internal class LateinitLowering(val context: Context): FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitProperty(declaration: IrProperty): IrStatement {
if (declaration.descriptor.isLateInit)
transformGetter(declaration.descriptor, declaration.getter!!)
return declaration
}
private fun transformGetter(propertyDescriptor: PropertyDescriptor, getter: IrFunction) {
val startOffset = getter.startOffset
val endOffset = getter.endOffset
val irBuilder = context.createIrBuilder(getter.descriptor, startOffset, endOffset)
irBuilder.run {
val block = irBlock(propertyDescriptor.type)
val resultVar = scope.createTemporaryVariable(irGetField(irThis(), propertyDescriptor))
block.statements.add(resultVar)
val throwIfNull = irIfThenElse(context.builtIns.nothingType,
irNotEquals(irGet(resultVar.descriptor), irNull()),
irReturn(irGet(resultVar.descriptor)),
irCall(throwErrorFunction))
block.statements.add(throwIfNull)
getter.body = IrExpressionBodyImpl(startOffset, endOffset, block)
}
}
})
}
private val throwErrorFunction = context.builtIns.getKonanInternalFunctions("ThrowUninitializedPropertyAccessException").single()
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock
= IrBlockImpl(startOffset, endOffset, type)
private fun IrBuilderWithScope.irGetField(receiver: IrExpression?, property: PropertyDescriptor): IrExpression
= IrGetFieldImpl(startOffset, endOffset, property, receiver)
}
@@ -24,6 +24,10 @@ fun ThrowNoWhenBranchMatchedException(): Nothing {
throw NoWhenBranchMatchedException()
}
fun ThrowUninitializedPropertyAccessException(): Nothing {
throw UninitializedPropertyAccessException()
}
@ExportForCppRuntime
internal fun TheEmptyString() = ""
@@ -176,6 +176,15 @@ public open class NoWhenBranchMatchedException : RuntimeException {
}
}
public open class UninitializedPropertyAccessException : RuntimeException {
constructor() : super() {
}
constructor(s: String) : super(s) {
}
}
public open class OutOfMemoryError : Error {
constructor() : super() {