JVM_IR: do not generate $assertionsDisabled twice during inlining
This commit is contained in:
@@ -121,7 +121,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
// In case `codegen.visitor` is `<clinit>`, initializer for the `$assertionsDisabled` field
|
||||
// needs to be inserted before the code that actually uses it.
|
||||
generateAssertFieldIfNeeded(info)
|
||||
if (info.generateAssertField) {
|
||||
generateAssertField()
|
||||
}
|
||||
|
||||
val shouldSpillStack = node.requiresEmptyStackOnEntry()
|
||||
if (shouldSpillStack) {
|
||||
@@ -193,7 +195,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
processor.substituteLocalVarTable(intoNode)
|
||||
}
|
||||
|
||||
protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext)
|
||||
protected abstract fun generateAssertField()
|
||||
|
||||
private fun isInlinedToInlineFunInKotlinRuntime(): Boolean {
|
||||
val codegen = this.codegen as? ExpressionCodegen ?: return false
|
||||
|
||||
@@ -51,11 +51,8 @@ class PsiInlineCodegen(
|
||||
state.languageVersionSettings, state.unifiedNullChecks
|
||||
),
|
||||
), CallGenerator {
|
||||
override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
|
||||
if (info.generateAssertField) {
|
||||
codegen.parentCodegen.generateAssertField()
|
||||
}
|
||||
}
|
||||
override fun generateAssertField() =
|
||||
codegen.parentCodegen.generateAssertField()
|
||||
|
||||
override fun genCallInner(
|
||||
callableMethod: Callable,
|
||||
|
||||
+6
@@ -894,6 +894,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
+8
-10
@@ -197,22 +197,19 @@ class ClassCodegen private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun generateAssertFieldIfNeeded(generatingClInit: Boolean): IrExpression? {
|
||||
if (irClass.hasAssertionsDisabledField(context))
|
||||
return null
|
||||
val topLevelClass = generateSequence(this) { it.parentClassCodegen }.last().irClass
|
||||
val field = irClass.buildAssertionsDisabledField(context, topLevelClass)
|
||||
generateField(field)
|
||||
// Normally, `InitializersLowering` would move the initializer to <clinit>, but
|
||||
// it's obviously too late for that.
|
||||
val init = IrSetFieldImpl(
|
||||
field.startOffset, field.endOffset, field.symbol, null,
|
||||
field.initializer!!.expression, context.irBuiltIns.unitType
|
||||
)
|
||||
irClass.declarations.add(0, field)
|
||||
// Normally, `InitializersLowering` would move the initializer to <clinit>, but it's obviously too late for that.
|
||||
val init = with(field) {
|
||||
IrSetFieldImpl(startOffset, endOffset, symbol, null, initializer!!.expression, context.irBuiltIns.unitType)
|
||||
}
|
||||
if (generatingClInit) {
|
||||
// Too late to modify the IR; have to ask the currently active `ExpressionCodegen`
|
||||
// to generate this statement directly.
|
||||
// Too late to modify the IR; have to ask the currently active `ExpressionCodegen` to generate this statement
|
||||
// directly. At least we know that nothing before this point uses the field.
|
||||
return init
|
||||
}
|
||||
val classInitializer = irClass.functions.singleOrNull { it.name.asString() == "<clinit>" } ?: irClass.addFunction {
|
||||
@@ -221,6 +218,7 @@ class ClassCodegen private constructor(
|
||||
}.apply {
|
||||
body = IrBlockBodyImpl(startOffset, endOffset)
|
||||
}
|
||||
// Should be initialized first in case some inline function call in `<clinit>` also uses assertions.
|
||||
(classInitializer.body as IrBlockBody).statements.add(0, init)
|
||||
return null
|
||||
}
|
||||
|
||||
+5
-7
@@ -46,13 +46,11 @@ class IrInlineCodegen(
|
||||
InlineCodegen<ExpressionCodegen>(codegen, state, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner),
|
||||
IrInlineCallGenerator {
|
||||
|
||||
override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
|
||||
if (info.generateAssertField) {
|
||||
// May be inlining code into `<clinit>`, in which case it's too late to modify the IR and
|
||||
// `generateAssertFieldIfNeeded` will return a statement for which we need to emit bytecode.
|
||||
val isClInit = info.callSiteInfo.method.name == "<clinit>"
|
||||
codegen.classCodegen.generateAssertFieldIfNeeded(isClInit)?.accept(codegen, BlockInfo())?.discard()
|
||||
}
|
||||
override fun generateAssertField() {
|
||||
// May be inlining code into `<clinit>`, in which case it's too late to modify the IR and
|
||||
// `generateAssertFieldIfNeeded` will return a statement for which we need to emit bytecode.
|
||||
val isClInit = sourceCompiler.inlineCallSiteInfo.method.name == "<clinit>"
|
||||
codegen.classCodegen.generateAssertFieldIfNeeded(isClInit)?.accept(codegen, BlockInfo())?.discard()
|
||||
}
|
||||
|
||||
override fun genValueAndPut(
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// FULL_JDK
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// ASSERTIONS_MODE: jvm
|
||||
// FILE: inline.kt
|
||||
package test
|
||||
|
||||
class A {
|
||||
inline fun assert(message: String): Nothing {
|
||||
assert(false) { message }
|
||||
throw IllegalStateException("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: inlineSite.kt
|
||||
import test.*
|
||||
|
||||
class Checker {
|
||||
fun o(): Nothing = A().assert("O")
|
||||
fun k(): Nothing = A().assert("K")
|
||||
}
|
||||
|
||||
class Dummy
|
||||
|
||||
fun box(): String {
|
||||
var c = Dummy::class.java.classLoader.apply {
|
||||
setDefaultAssertionStatus(true)
|
||||
}.loadClass("Checker").newInstance() as Checker
|
||||
val o = try { c.o() } catch (e: AssertionError) { e.message }
|
||||
val k = try { c.k() } catch (e: AssertionError) { e.message }
|
||||
return o + k
|
||||
}
|
||||
+6
@@ -894,6 +894,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
+6
@@ -894,6 +894,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
+6
@@ -894,6 +894,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
+6
@@ -894,6 +894,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
+6
@@ -894,6 +894,12 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
+6
@@ -894,6 +894,12 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineIntoTwoMethods.kt")
|
||||
public void testJvmInlineIntoTwoMethods() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/assert/jvmInlineIntoTwoMethods.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user