JVM IR: Don't generate line numbers and null checks in SAM wrapper constructors

This commit is contained in:
Steven Schäfer
2020-11-02 14:40:08 +01:00
committed by Alexander Udalov
parent 68e2d0d245
commit 8574cb4466
7 changed files with 61 additions and 5 deletions
@@ -4314,6 +4314,11 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("samWrapperConstructorNonSynthetic.kt")
public void testSamWrapperConstructorNonSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt");
}
@TestMetadata("samWrapperForNullInitialization.kt")
public void testSamWrapperForNullInitialization() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt");
@@ -69,6 +69,10 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
protected open fun getWrappedFunctionType(klass: IrClass): IrType =
klass.defaultType
protected open fun IrFunctionBuilder.setConstructorSourceRange(createFor: IrElement) {
setSourceRange(createFor)
}
abstract val IrType.needEqualsHashCodeMethods: Boolean
open val inInlineFunctionScope get() = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false }
@@ -187,10 +191,10 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
}
subclass.addConstructor {
origin = subclass.origin
origin = IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION
isPrimary = true
visibility = wrapperVisibility
setSourceRange(createFor)
setConstructorSourceRange(createFor)
}.apply {
val parameter = addValueParameter {
name = field.name
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.isMultifileBridge
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*
import org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getNameForReceiverParameter
import org.jetbrains.kotlin.codegen.coroutines.SuspensionPointKind
import org.jetbrains.kotlin.codegen.coroutines.generateCoroutineSuspendedCheck
import org.jetbrains.kotlin.codegen.inline.*
@@ -48,7 +48,8 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
@@ -285,7 +286,9 @@ class ExpressionCodegen(
irFunction.origin.isSynthetic ||
// TODO: refine this condition to not generate nullability assertions on parameters
// corresponding to captured variables and anonymous object super constructor arguments
(irFunction is IrConstructor && irFunction.parentAsClass.isAnonymousObject) ||
(irFunction is IrConstructor &&
(irFunction.parentAsClass.isAnonymousObject ||
irFunction.parentAsClass.origin == IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION)) ||
// TODO: Implement this as a lowering, so that we can more easily exclude generated methods.
irFunction.origin == JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD ||
// Although these are accessible from Java, the functions they bridge to already have the assertions.
@@ -12,6 +12,9 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.rawType
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -47,6 +50,13 @@ private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : Sing
override fun getWrappedFunctionType(klass: IrClass): IrType =
klass.symbol.rawType(context as JvmBackendContext)
// The constructor of a SAM wrapper is non-synthetic and should not have line numbers.
// Otherwise the debugger will try to step into it.
override fun IrFunctionBuilder.setConstructorSourceRange(createFor: IrElement) {
startOffset = UNDEFINED_OFFSET
endOffset = UNDEFINED_OFFSET
}
private val IrType.isKotlinFunInterface: Boolean
get() = getClass()?.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
@@ -0,0 +1,24 @@
// FILE: J.java
public class J {
public static void g(Runnable r) {
r.run();
}
}
// FILE: test.kt
fun nonInlineFun() {
val f = {}
J.g(f)
}
inline fun inlineFun() {
val f = {}
J.g(f)
}
// The SAM wrapper constructor is public inside of inline functions.
// It has no other flags. In particular, it is not synthetic.
// 1 access flags 0x0\n\s*<init>\(Lkotlin/jvm/functions/Function0;\)V
// 1 access flags 0x1\n\s*public <init>\(Lkotlin/jvm/functions/Function0;\)V
@@ -4386,6 +4386,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("samWrapperConstructorNonSynthetic.kt")
public void testSamWrapperConstructorNonSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt");
}
@TestMetadata("samWrapperForNullInitialization.kt")
public void testSamWrapperForNullInitialization() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt");
@@ -4314,6 +4314,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("samWrapperConstructorNonSynthetic.kt")
public void testSamWrapperConstructorNonSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperConstructorNonSynthetic.kt");
}
@TestMetadata("samWrapperForNullInitialization.kt")
public void testSamWrapperForNullInitialization() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt");