From 29a14e2330f4d8b1b4e92291693d901b182daf22 Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 11 Nov 2019 16:24:25 +0100 Subject: [PATCH] JVM_IR: resolve inline fake overrides before codegen See KT-33054 and KT-29242. --- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 1 + .../backend/jvm/codegen/ExpressionCodegen.kt | 7 +-- .../backend/jvm/lower/ResolveInlineCalls.kt | 43 +++++++++++++++++++ compiler/testData/codegen/box/jvm8/kt29242.kt | 24 +++++++++++ compiler/testData/codegen/box/jvm8/kt33054.kt | 19 ++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 +++++ .../LightAnalysisModeTestGenerated.java | 10 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 +++++ 8 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt create mode 100644 compiler/testData/codegen/box/jvm8/kt29242.kt create mode 100644 compiler/testData/codegen/box/jvm8/kt33054.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 68d4f74bb01..b33f8c3be3a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -298,6 +298,7 @@ private val jvmFilePhases = additionalClassAnnotationPhase then typeOperatorLowering then replaceKFunctionInvokeWithFunctionInvokePhase then + resolveInlineCallsPhase then checkLocalNamesWithOldBackendPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index f54f05cada9..dfc207eb225 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -965,9 +965,8 @@ class ExpressionCodegen( } } - val original = (callee as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction val methodOwner = callee.parent.safeAs()?.let(typeMapper::mapClass) ?: MethodSignatureMapper.FAKE_OWNER_TYPE - val sourceCompiler = IrSourceCompilerForInline(state, element, original, this, data) + val sourceCompiler = IrSourceCompilerForInline(state, element, callee, this, data) val reifiedTypeInliner = ReifiedTypeInliner(mappings, object : ReifiedTypeInliner.IntrinsicsSupport { override fun putClassInstance(v: InstructionAdapter, type: IrType) { @@ -977,9 +976,7 @@ class ExpressionCodegen( override fun toKotlinType(type: IrType): KotlinType = type.toKotlinType() }, IrTypeCheckerContext(context.irBuiltIns), state.languageVersionSettings) - return IrInlineCodegen( - this, state, original.descriptor, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner - ) + return IrInlineCodegen(this, state, callee.descriptor, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner) } override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt new file mode 100644 index 00000000000..2ee3e7f3ac5 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2019 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.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +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.util.copyTypeAndValueArgumentsFrom +import org.jetbrains.kotlin.ir.util.resolveFakeOverride +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid + +internal val resolveInlineCallsPhase = makeIrFilePhase( + ::ResolveInlineCalls, + name = "ResolveInlineCalls", + description = "Statically resolve calls to inline methods to particular implementations" +) + +class ResolveInlineCalls(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { + override fun lower(irFile: IrFile) = irFile.transformChildrenVoid() + + override fun visitCall(expression: IrCall): IrExpression { + if (!expression.symbol.owner.isInlineFunctionCall(context)) + return super.visitCall(expression) + val maybeFakeOverride = expression.symbol.owner as? IrSimpleFunction + ?: return super.visitCall(expression) + val resolved = maybeFakeOverride.resolveFakeOverride() + ?: return super.visitCall(expression) + return super.visitCall(with(expression) { + IrCallImpl(startOffset, endOffset, type, resolved.symbol, superQualifierSymbol).apply { + copyTypeAndValueArgumentsFrom(expression) + } + }) + } +} diff --git a/compiler/testData/codegen/box/jvm8/kt29242.kt b/compiler/testData/codegen/box/jvm8/kt29242.kt new file mode 100644 index 00000000000..5a528d0c43b --- /dev/null +++ b/compiler/testData/codegen/box/jvm8/kt29242.kt @@ -0,0 +1,24 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// JVM_TARGET: 1.8 +// See also kt33054.kt + +fun causesVerifyErrorSample(): Sample = Sample + .Success(true) + .flatMap { Sample.Failure(RuntimeException()) } + +sealed class Sample { + inline fun flatMap(f: (T) -> Sample): Sample = + when (this) { + is Failure -> this + is Success -> f(this.value) + } + + data class Failure(val exception: Throwable): Sample() + data class Success(val value: T): Sample() +} + +fun box(): String { + causesVerifyErrorSample() + return "OK" +} diff --git a/compiler/testData/codegen/box/jvm8/kt33054.kt b/compiler/testData/codegen/box/jvm8/kt33054.kt new file mode 100644 index 00000000000..6472d777dc2 --- /dev/null +++ b/compiler/testData/codegen/box/jvm8/kt33054.kt @@ -0,0 +1,19 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// JVM_TARGET: 1.8 + +open class A(val x: String) { + inline fun f() = if (this is C) this else A("O") + + val y + inline get() = if (this is C) this else A("K") +} + +class B : A("unused") +class C : A("unused") + +// If the receiver is not CHECKCASTed to A when inlining, asm will infer Object +// for the result of `if` in `f` instead of A when generating stack maps because +// one branch has type A while the other has type B (a subtype of A, but asm +// does not know that). This would cause a JVM validation error. +fun box() = B().f().x + B().y.x diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 743ebcb6c59..29a2e5aa907 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -14519,6 +14519,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/jvm8/kt16588.kt"); } + @TestMetadata("kt29242.kt") + public void testKt29242() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/kt29242.kt"); + } + + @TestMetadata("kt33054.kt") + public void testKt33054() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/kt33054.kt"); + } + @TestMetadata("kt6301.kt") public void testKt6301() throws Exception { runTest("compiler/testData/codegen/box/jvm8/kt6301.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1f19a9d81d1..cde374e7eac 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -14446,6 +14446,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class Jvm8 extends AbstractLightAnalysisModeTest { + @TestMetadata("kt29242.kt") + public void ignoreKt29242() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/kt29242.kt"); + } + + @TestMetadata("kt33054.kt") + public void ignoreKt33054() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/kt33054.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index b9ffc252afe..9de13d8c864 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13404,6 +13404,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/jvm8/kt16588.kt"); } + @TestMetadata("kt29242.kt") + public void testKt29242() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/kt29242.kt"); + } + + @TestMetadata("kt33054.kt") + public void testKt33054() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/kt33054.kt"); + } + @TestMetadata("kt6301.kt") public void testKt6301() throws Exception { runTest("compiler/testData/codegen/box/jvm8/kt6301.kt");