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 =
@@ -357,6 +363,7 @@ private val jvmFilePhases =
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,7 +77,8 @@ 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 =
createClass(FqName("java.lang.UnsupportedOperationException")) { klass ->
klass.addConstructor().apply { klass.addConstructor().apply {
addValueParameter("message", irBuiltIns.stringType.makeNullable()) addValueParameter("message", irBuiltIns.stringType.makeNullable())
} }
@@ -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()