KNVE: support in JVM_IR and JS_IR

This commit is contained in:
Dmitry Petrov
2020-04-20 14:45:18 +03:00
parent b06780988d
commit 05cb0e8994
12 changed files with 150 additions and 14 deletions
@@ -232,6 +232,9 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, symbolTable
abstract val ThrowUninitializedPropertyAccessException: IrSimpleFunctionSymbol
open val ThrowKotlinNothingValueException: IrSimpleFunctionSymbol
get() = TODO("Support KotlinNothingValueException in Kotlin/Native and make this val abstract")
abstract val stringBuilder: IrClassSymbol
abstract val defaultConstructorMarker: IrClassSymbol
@@ -0,0 +1,71 @@
/*
* 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.backend.common.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrSymbolDeclaration
import org.jetbrains.kotlin.ir.expressions.IrBody
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.IrSymbol
import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
class KotlinNothingValueExceptionLowering(val backendContext: CommonBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(
Transformer((container as IrSymbolDeclaration<*>).symbol)
)
}
private inner class Transformer(val parent: IrSymbol) : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression =
if (expression.type.isNothing()) {
// Replace call 'foo' of type 'kotlin.Nothing' with a block:
//
// {
// [ call 'foo' with type: 'kotlin.Unit' ]
// call ThrowKotlinNothingValueException(): Nothing
// }: Nothing
//
// Changing type of 'foo' to 'kotlin.Unit' is requires so that the 'ThrowKotlinNothingValueException(): Nothing'
// is not considered dead code and is not removed.
// Note that type 'kotlin.Nothing' might be inferred in some cases of projected types.
// See KT-30330 for an example of such code where call of type 'kotlin.Nothing' terminates and produces some value
// (although doing so by subverting the type system).
backendContext.createIrBuilder(parent, expression.startOffset, expression.endOffset).run {
irBlock(expression, null, context.irBuiltIns.nothingType) {
+changeTypeToUnit(expression)
+irCall(backendContext.ir.symbols.ThrowKotlinNothingValueException)
}
}
} else {
expression
}
private fun changeTypeToUnit(call: IrCall): IrCall =
IrCallImpl(
call.startOffset, call.endOffset,
backendContext.irBuiltIns.unitType,
call.symbol,
call.typeArgumentsCount, call.valueArgumentsCount, call.origin, call.superQualifierSymbol
).also { newCall ->
for (i in 0 until call.typeArgumentsCount) {
newCall.putTypeArgument(i, call.getTypeArgument(i))
}
newCall.dispatchReceiver = call.dispatchReceiver
newCall.extensionReceiver = call.extensionReceiver
for (i in 0 until call.valueArgumentsCount) {
newCall.putValueArgument(i, call.getValueArgument(i))
}
}
}
}
@@ -194,6 +194,9 @@ class JsIrBackendContext(
override val ThrowUninitializedPropertyAccessException =
symbolTable.referenceSimpleFunction(getFunctions(FqName("kotlin.throwUninitializedPropertyAccessException")).single())
override val ThrowKotlinNothingValueException: IrSimpleFunctionSymbol =
symbolTable.referenceSimpleFunction(getFunctions(FqName("kotlin.throwKotlinNothingValueException")).single())
override val defaultConstructorMarker =
symbolTable.referenceClass(context.getJsInternalClass("DefaultConstructorMarker"))
@@ -215,7 +218,8 @@ class JsIrBackendContext(
override val coroutineContextGetter = symbolTable.referenceSimpleFunction(context.coroutineContextProperty.getter!!)
override val suspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction(getJsInternalFunction(COROUTINE_SUSPEND_OR_RETURN_JS_NAME))
override val suspendCoroutineUninterceptedOrReturn =
symbolTable.referenceSimpleFunction(getJsInternalFunction(COROUTINE_SUSPEND_OR_RETURN_JS_NAME))
override val coroutineGetContext = symbolTable.referenceSimpleFunction(getJsInternalFunction(GET_COROUTINE_CONTEXT_NAME))
@@ -159,6 +159,12 @@ private val lateinitUsageLoweringPhase = makeBodyLoweringPhase(
description = "Insert checks for lateinit field references"
)
private val kotlinNothingValueExceptionPhase = makeBodyLoweringPhase(
::KotlinNothingValueExceptionLowering,
name = "KotlinNothingValueException",
description = "Throw proper exception for calls returning value of type 'kotlin.Nothing'"
)
private val stripTypeAliasDeclarationsPhase = makeDeclarationTransformerPhase(
{ StripTypeAliasDeclarationsLowering() },
name = "StripTypeAliasDeclarations",
@@ -638,6 +644,7 @@ val loweringList = listOf<Lowering>(
annotationConstructorLowering,
initializersLoweringPhase,
initializersCleanupLoweringPhase,
kotlinNothingValueExceptionPhase,
// Common prefix ends
enumEntryInstancesLoweringPhase,
enumEntryInstancesBodyLoweringPhase,
@@ -118,7 +118,8 @@ internal val localDeclarationsPhase = makeIrFilePhase<CommonBackendContext>(
override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): Visibility =
if (declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
declaration.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
declaration.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE) {
declaration.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
) {
scopedVisibility(inInlineFunctionScope)
} else {
declaration.visibility
@@ -255,12 +256,17 @@ private val syntheticAccessorPhase = makeIrFilePhase(
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase)
)
private val tailrecPhase = makeIrFilePhase<JvmBackendContext>(
private val tailrecPhase = makeIrFilePhase(
::JvmTailrecLowering,
name = "Tailrec",
description = "Handle tailrec calls"
)
private val kotlinNothingValueExceptionPhase = makeIrFilePhase(
::KotlinNothingValueExceptionLowering,
name = "KotlinNothingValueException",
description = "Throw proper exception for calls returning value of type 'kotlin.Nothing'"
)
@Suppress("Reformat")
private val jvmFilePhases =
@@ -353,10 +359,11 @@ private val jvmFilePhases =
jvmArgumentNullabilityAssertions then
toArrayPhase then
jvmOptimizationLoweringPhase then
ifNullExpressionsFusionPhase then
ifNullExpressionsFusionPhase then
additionalClassAnnotationPhase then
typeOperatorLowering then
replaceKFunctionInvokeWithFunctionInvokePhase then
kotlinNothingValueExceptionPhase then
checkLocalNamesWithOldBackendPhase then
@@ -3,6 +3,8 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("PropertyName")
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.Symbols
@@ -21,7 +23,6 @@ import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.*
@@ -76,11 +77,12 @@ class JvmSymbols(
override val ThrowTypeCastException: IrFunctionSymbol =
typeCastExceptionClass.constructors.single()
private val unsupportedOperationExceptionClass: IrClassSymbol = createClass(FqName("java.lang.UnsupportedOperationException")) { klass ->
klass.addConstructor().apply {
addValueParameter("message", irBuiltIns.stringType.makeNullable())
private val unsupportedOperationExceptionClass: IrClassSymbol =
createClass(FqName("java.lang.UnsupportedOperationException")) { klass ->
klass.addConstructor().apply {
addValueParameter("message", irBuiltIns.stringType.makeNullable())
}
}
}
val ThrowUnsupportOperationExceptionClass: IrFunctionSymbol =
unsupportedOperationExceptionClass.constructors.single()
@@ -679,6 +681,15 @@ class JvmSymbols(
val runSuspendFunction: IrSimpleFunctionSymbol =
kotlinCoroutinesJvmInternalRunSuspendKt.functionByName("runSuspend")
override val ThrowKotlinNothingValueException: IrSimpleFunctionSymbol =
buildFun {
name = Name.identifier("ThrowKotlinNothingValueException")
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
returnType = irBuiltIns.nothingType
}.apply {
parent = kotlinJvmInternalPackage
}.symbol
}
private fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol =
@@ -451,8 +451,6 @@ class ExpressionCodegen(
return when {
expression.type.isNothing() -> {
mv.aconst(null)
mv.athrow()
unitValue
}
expression is IrConstructorCall ->
@@ -112,7 +112,8 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
irBuiltIns.dataClassArrayMemberToStringSymbol.toKey()!! to IrDataClassArrayMemberToString,
symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce,
symbols.signatureStringIntrinsic.toKey()!! to SignatureString,
symbols.reassignParameterIntrinsic.toKey()!! to ReassignParameter
symbols.reassignParameterIntrinsic.toKey()!! to ReassignParameter,
symbols.ThrowKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException
) +
numberConversionMethods() +
unaryFunForPrimitives("plus", UnaryPlus) +
@@ -0,0 +1,29 @@
/*
* 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.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Type
object ThrowKotlinNothingValueException : IntrinsicMethod() {
override fun toCallable(
expression: IrFunctionAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction =
IrIntrinsicFunction.create(expression, signature, context) { mv ->
if (context.state.useKotlinNothingValueException) {
mv.anew(Type.getObjectType("kotlin/KotlinNothingValueException"))
mv.dup()
mv.invokespecial("kotlin/KotlinNothingValueException", "<init>", "()V", false)
} else {
mv.aconst(null)
}
mv.athrow()
}
}
@@ -34,6 +34,8 @@ class WasmSymbols(
get() = TODO()
override val ThrowUninitializedPropertyAccessException
get() = TODO()
override val ThrowKotlinNothingValueException: IrSimpleFunctionSymbol
get() = TODO()
override val defaultConstructorMarker
get() = TODO()
override val stringBuilder
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS, JS_IR, JVM_IR, NATIVE
// IGNORE_BACKEND: JS, NATIVE
fun <T> something(): T = Any() as T
+4
View File
@@ -9,6 +9,10 @@ package kotlin
internal fun throwUninitializedPropertyAccessException(name: String): Nothing =
throw UninitializedPropertyAccessException("lateinit property $name has not been initialized")
@PublishedApi
internal fun throwKotlinNothingValueException(): Nothing =
throw KotlinNothingValueException()
internal fun noWhenBranchMatchedException(): Nothing = throw NoWhenBranchMatchedException()