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 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 stringBuilder: IrClassSymbol
abstract val defaultConstructorMarker: 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 = override val ThrowUninitializedPropertyAccessException =
symbolTable.referenceSimpleFunction(getFunctions(FqName("kotlin.throwUninitializedPropertyAccessException")).single()) symbolTable.referenceSimpleFunction(getFunctions(FqName("kotlin.throwUninitializedPropertyAccessException")).single())
override val ThrowKotlinNothingValueException: IrSimpleFunctionSymbol =
symbolTable.referenceSimpleFunction(getFunctions(FqName("kotlin.throwKotlinNothingValueException")).single())
override val defaultConstructorMarker = override val defaultConstructorMarker =
symbolTable.referenceClass(context.getJsInternalClass("DefaultConstructorMarker")) symbolTable.referenceClass(context.getJsInternalClass("DefaultConstructorMarker"))
@@ -215,7 +218,8 @@ class JsIrBackendContext(
override val coroutineContextGetter = symbolTable.referenceSimpleFunction(context.coroutineContextProperty.getter!!) 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)) 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" 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( private val stripTypeAliasDeclarationsPhase = makeDeclarationTransformerPhase(
{ StripTypeAliasDeclarationsLowering() }, { StripTypeAliasDeclarationsLowering() },
name = "StripTypeAliasDeclarations", name = "StripTypeAliasDeclarations",
@@ -638,6 +644,7 @@ val loweringList = listOf<Lowering>(
annotationConstructorLowering, annotationConstructorLowering,
initializersLoweringPhase, initializersLoweringPhase,
initializersCleanupLoweringPhase, initializersCleanupLoweringPhase,
kotlinNothingValueExceptionPhase,
// Common prefix ends // Common prefix ends
enumEntryInstancesLoweringPhase, enumEntryInstancesLoweringPhase,
enumEntryInstancesBodyLoweringPhase, enumEntryInstancesBodyLoweringPhase,
@@ -118,7 +118,8 @@ internal val localDeclarationsPhase = makeIrFilePhase<CommonBackendContext>(
override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): Visibility = override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): Visibility =
if (declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL || if (declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
declaration.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL || declaration.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
declaration.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE) { declaration.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
) {
scopedVisibility(inInlineFunctionScope) scopedVisibility(inInlineFunctionScope)
} else { } else {
declaration.visibility declaration.visibility
@@ -255,12 +256,17 @@ private val syntheticAccessorPhase = makeIrFilePhase(
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase) prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase)
) )
private val tailrecPhase = makeIrFilePhase<JvmBackendContext>( private val tailrecPhase = makeIrFilePhase(
::JvmTailrecLowering, ::JvmTailrecLowering,
name = "Tailrec", name = "Tailrec",
description = "Handle tailrec calls" 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") @Suppress("Reformat")
private val jvmFilePhases = private val jvmFilePhases =
@@ -353,10 +359,11 @@ private val jvmFilePhases =
jvmArgumentNullabilityAssertions then jvmArgumentNullabilityAssertions then
toArrayPhase then toArrayPhase then
jvmOptimizationLoweringPhase then jvmOptimizationLoweringPhase then
ifNullExpressionsFusionPhase then ifNullExpressionsFusionPhase then
additionalClassAnnotationPhase then additionalClassAnnotationPhase then
typeOperatorLowering then typeOperatorLowering then
replaceKFunctionInvokeWithFunctionInvokePhase then replaceKFunctionInvokeWithFunctionInvokePhase then
kotlinNothingValueExceptionPhase then
checkLocalNamesWithOldBackendPhase 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. * 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 package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.Symbols 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.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin 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.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
@@ -76,11 +77,12 @@ class JvmSymbols(
override val ThrowTypeCastException: IrFunctionSymbol = override val ThrowTypeCastException: IrFunctionSymbol =
typeCastExceptionClass.constructors.single() typeCastExceptionClass.constructors.single()
private val unsupportedOperationExceptionClass: IrClassSymbol = createClass(FqName("java.lang.UnsupportedOperationException")) { klass -> private val unsupportedOperationExceptionClass: IrClassSymbol =
klass.addConstructor().apply { createClass(FqName("java.lang.UnsupportedOperationException")) { klass ->
addValueParameter("message", irBuiltIns.stringType.makeNullable()) klass.addConstructor().apply {
addValueParameter("message", irBuiltIns.stringType.makeNullable())
}
} }
}
val ThrowUnsupportOperationExceptionClass: IrFunctionSymbol = val ThrowUnsupportOperationExceptionClass: IrFunctionSymbol =
unsupportedOperationExceptionClass.constructors.single() unsupportedOperationExceptionClass.constructors.single()
@@ -679,6 +681,15 @@ class JvmSymbols(
val runSuspendFunction: IrSimpleFunctionSymbol = val runSuspendFunction: IrSimpleFunctionSymbol =
kotlinCoroutinesJvmInternalRunSuspendKt.functionByName("runSuspend") 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 = private fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol =
@@ -451,8 +451,6 @@ class ExpressionCodegen(
return when { return when {
expression.type.isNothing() -> { expression.type.isNothing() -> {
mv.aconst(null)
mv.athrow()
unitValue unitValue
} }
expression is IrConstructorCall -> expression is IrConstructorCall ->
@@ -112,7 +112,8 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
irBuiltIns.dataClassArrayMemberToStringSymbol.toKey()!! to IrDataClassArrayMemberToString, irBuiltIns.dataClassArrayMemberToStringSymbol.toKey()!! to IrDataClassArrayMemberToString,
symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce, symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce,
symbols.signatureStringIntrinsic.toKey()!! to SignatureString, symbols.signatureStringIntrinsic.toKey()!! to SignatureString,
symbols.reassignParameterIntrinsic.toKey()!! to ReassignParameter symbols.reassignParameterIntrinsic.toKey()!! to ReassignParameter,
symbols.ThrowKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException
) + ) +
numberConversionMethods() + numberConversionMethods() +
unaryFunForPrimitives("plus", UnaryPlus) + 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() get() = TODO()
override val ThrowUninitializedPropertyAccessException override val ThrowUninitializedPropertyAccessException
get() = TODO() get() = TODO()
override val ThrowKotlinNothingValueException: IrSimpleFunctionSymbol
get() = TODO()
override val defaultConstructorMarker override val defaultConstructorMarker
get() = TODO() get() = TODO()
override val stringBuilder override val stringBuilder
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND: JS, NATIVE
// IGNORE_BACKEND: JS, JS_IR, JVM_IR, NATIVE
fun <T> something(): T = Any() as T fun <T> something(): T = Any() as T
+4
View File
@@ -9,6 +9,10 @@ package kotlin
internal fun throwUninitializedPropertyAccessException(name: String): Nothing = internal fun throwUninitializedPropertyAccessException(name: String): Nothing =
throw UninitializedPropertyAccessException("lateinit property $name has not been initialized") throw UninitializedPropertyAccessException("lateinit property $name has not been initialized")
@PublishedApi
internal fun throwKotlinNothingValueException(): Nothing =
throw KotlinNothingValueException()
internal fun noWhenBranchMatchedException(): Nothing = throw NoWhenBranchMatchedException() internal fun noWhenBranchMatchedException(): Nothing = throw NoWhenBranchMatchedException()