[JVM IR] Added null-checks of handler for non-super $default calls

This commit is contained in:
Kristoffer Andersen
2020-02-03 13:46:43 +01:00
committed by Alexander Udalov
parent fe50bb4b93
commit c1d350f8f3
11 changed files with 92 additions and 17 deletions
@@ -54,8 +54,9 @@ open class DefaultArgumentStubGenerator(
private fun lower(irFunction: IrFunction): List<IrFunction>? {
val visibility = defaultArgumentStubVisibility(irFunction)
val newIrFunction = irFunction.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods, forceSetOverrideSymbols, visibility)
?: return null
val newIrFunction =
irFunction.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods, forceSetOverrideSymbols, visibility)
?: return null
if (newIrFunction.origin == IrDeclarationOrigin.FAKE_OVERRIDE) {
return listOf(irFunction, newIrFunction)
}
@@ -90,6 +91,8 @@ open class DefaultArgumentStubGenerator(
newIrFunction.valueParameters[it.index]
}
generateSuperCallHandlerCheckIfNeeded(irFunction, newIrFunction)
var sourceParameterIndex = -1
for (valueParameter in irFunction.valueParameters) {
if (!valueParameter.isMovedReceiver()) {
@@ -180,6 +183,12 @@ open class DefaultArgumentStubGenerator(
} else dispatchCall
}
protected open fun IrBlockBodyBuilder.generateSuperCallHandlerCheckIfNeeded(
irFunction: IrFunction,
newIrFunction: IrFunction) {
//NO-OP Stub
}
protected open fun needSpecialDispatch(irFunction: IrSimpleFunction) = false
protected open fun IrBlockBodyBuilder.generateHandleCall(
handlerDeclaration: IrValueParameter,
@@ -506,7 +515,11 @@ private fun IrFunction.generateDefaultsFunctionImpl(
val markerType = context.ir.symbols.defaultConstructorMarker.defaultType.makeNullable()
newFunction.addValueParameter("marker".synthesizedString, markerType, IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER)
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
newFunction.addValueParameter("handler".synthesizedString, context.irBuiltIns.anyNType, IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION)
newFunction.addValueParameter(
"handler".synthesizedString,
context.irBuiltIns.anyNType,
IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION
)
}
// TODO some annotations are needed (e.g. @JvmStatic), others need different values (e.g. @JvmName), the rest are redundant.
@@ -72,12 +72,16 @@ class JvmSymbols(
override val ThrowTypeCastException: IrFunctionSymbol =
typeCastExceptionClass.constructors.single()
val unsupportedOperationExceptionClass: IrClassSymbol = createClass(FqName("java.lang.UnsupportedOperationException")) { klass ->
private val unsupportedOperationExceptionClass: IrClassSymbol = createClass(FqName("java.lang.UnsupportedOperationException")) { klass ->
klass.addConstructor().apply {
addValueParameter("message", irBuiltIns.stringType.makeNullable())
}
}
val ThrowUnsupportOperationExceptionClass: IrFunctionSymbol =
unsupportedOperationExceptionClass.constructors.single()
private fun createPackage(fqName: FqName): IrPackageFragment =
IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName)))
@@ -87,9 +87,7 @@ private class CollectionStubMethodLowering(val context: JvmBackendContext) : Cla
body = context.createIrBuilder(function.symbol).irBlockBody {
+irThrow(
irCall(
this@CollectionStubMethodLowering.context.ir.symbols.unsupportedOperationExceptionClass.owner.constructors.single {
it.valueParameters.size == 1 && it.valueParameters.single().type.isNullableString()
}
this@CollectionStubMethodLowering.context.ir.symbols.ThrowUnsupportOperationExceptionClass
).apply {
putValueArgument(0, irString("Operation is not supported for read-only collection"))
}
@@ -5,17 +5,17 @@
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ir.isFinalClass
import org.jetbrains.kotlin.backend.common.lower.DefaultArgumentStubGenerator
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub
import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
class JvmDefaultArgumentStubGenerator(override val context: JvmBackendContext) : DefaultArgumentStubGenerator(context, false, false) {
override fun IrBlockBodyBuilder.selectArgumentOrDefault(
@@ -47,4 +47,28 @@ class JvmDefaultArgumentStubGenerator(override val context: JvmBackendContext) :
}
override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub()
override fun IrBlockBodyBuilder.generateSuperCallHandlerCheckIfNeeded(
irFunction: IrFunction,
newIrFunction: IrFunction
) {
if (irFunction !is IrSimpleFunction
|| !this@JvmDefaultArgumentStubGenerator.context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()
|| irFunction.isTopLevelDeclaration
|| (irFunction.parent as? IrClass)?.isFinalClass == true
)
return
val handlerDeclaration = newIrFunction.valueParameters.last()
+irIfThen(
context.irBuiltIns.unitType,
irNot(irEqualsNull(irGet(handlerDeclaration))),
irThrow(irCall(this@JvmDefaultArgumentStubGenerator.context.ir.symbols.ThrowUnsupportOperationExceptionClass).apply {
putValueArgument(
0,
irString("Super calls with default arguments not supported in this target, function: ${irFunction.name.asString()}")
)
})
)
}
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -0,0 +1,20 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
open class O {
open fun foo(s: String = throw Error("Fail: this expression should not be evaluated")) {}
}
fun box(): String = try {
val f = O::class.java.declaredMethods.single { it.name == "foo\$default" }
f(null, O(), "s", 1, "non-null")
"Fail: exception should have been thrown"
} catch (e: Exception) {
val cause = e.cause
if (cause is UnsupportedOperationException) {
"OK"
} else {
cause.toString()
}
}
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36771 Missing special code for super calls to inline functions support in JVM_IR
//open modality to method handle check generation
open class A {
inline fun test(p: String = "OK"): String {
@@ -9369,6 +9369,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/defaultArguments/superCallCheck.kt");
}
@TestMetadata("superCallHandlerOrder.kt")
public void testSuperCallHandlerOrder() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/superCallHandlerOrder.kt");
}
@TestMetadata("useNextParamInLambda.kt")
public void testUseNextParamInLambda() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/useNextParamInLambda.kt");
@@ -9369,6 +9369,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/defaultArguments/superCallCheck.kt");
}
@TestMetadata("superCallHandlerOrder.kt")
public void testSuperCallHandlerOrder() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/superCallHandlerOrder.kt");
}
@TestMetadata("useNextParamInLambda.kt")
public void testUseNextParamInLambda() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/useNextParamInLambda.kt");
@@ -8239,6 +8239,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/defaultArguments/superCallCheck.kt");
}
@TestMetadata("superCallHandlerOrder.kt")
public void testSuperCallHandlerOrder() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/superCallHandlerOrder.kt");
}
@TestMetadata("useNextParamInLambda.kt")
public void testUseNextParamInLambda() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/useNextParamInLambda.kt");
@@ -8239,6 +8239,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/defaultArguments/superCallCheck.kt");
}
@TestMetadata("superCallHandlerOrder.kt")
public void testSuperCallHandlerOrder() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/superCallHandlerOrder.kt");
}
@TestMetadata("useNextParamInLambda.kt")
public void testUseNextParamInLambda() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/useNextParamInLambda.kt");