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
|
// In case `codegen.visitor` is `<clinit>`, initializer for the `$assertionsDisabled` field
|
||||||
// needs to be inserted before the code that actually uses it.
|
// needs to be inserted before the code that actually uses it.
|
||||||
generateAssertFieldIfNeeded(info)
|
if (info.generateAssertField) {
|
||||||
|
generateAssertField()
|
||||||
|
}
|
||||||
|
|
||||||
val shouldSpillStack = node.requiresEmptyStackOnEntry()
|
val shouldSpillStack = node.requiresEmptyStackOnEntry()
|
||||||
if (shouldSpillStack) {
|
if (shouldSpillStack) {
|
||||||
@@ -193,7 +195,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
processor.substituteLocalVarTable(intoNode)
|
processor.substituteLocalVarTable(intoNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext)
|
protected abstract fun generateAssertField()
|
||||||
|
|
||||||
private fun isInlinedToInlineFunInKotlinRuntime(): Boolean {
|
private fun isInlinedToInlineFunInKotlinRuntime(): Boolean {
|
||||||
val codegen = this.codegen as? ExpressionCodegen ?: return false
|
val codegen = this.codegen as? ExpressionCodegen ?: return false
|
||||||
|
|||||||
@@ -51,11 +51,8 @@ class PsiInlineCodegen(
|
|||||||
state.languageVersionSettings, state.unifiedNullChecks
|
state.languageVersionSettings, state.unifiedNullChecks
|
||||||
),
|
),
|
||||||
), CallGenerator {
|
), CallGenerator {
|
||||||
override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
|
override fun generateAssertField() =
|
||||||
if (info.generateAssertField) {
|
codegen.parentCodegen.generateAssertField()
|
||||||
codegen.parentCodegen.generateAssertField()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun genCallInner(
|
override fun genCallInner(
|
||||||
callableMethod: Callable,
|
callableMethod: Callable,
|
||||||
|
|||||||
+6
@@ -894,6 +894,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
|||||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
+8
-10
@@ -197,22 +197,19 @@ class ClassCodegen private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun generateAssertFieldIfNeeded(generatingClInit: Boolean): IrExpression? {
|
fun generateAssertFieldIfNeeded(generatingClInit: Boolean): IrExpression? {
|
||||||
if (irClass.hasAssertionsDisabledField(context))
|
if (irClass.hasAssertionsDisabledField(context))
|
||||||
return null
|
return null
|
||||||
val topLevelClass = generateSequence(this) { it.parentClassCodegen }.last().irClass
|
val topLevelClass = generateSequence(this) { it.parentClassCodegen }.last().irClass
|
||||||
val field = irClass.buildAssertionsDisabledField(context, topLevelClass)
|
val field = irClass.buildAssertionsDisabledField(context, topLevelClass)
|
||||||
generateField(field)
|
irClass.declarations.add(0, field)
|
||||||
// Normally, `InitializersLowering` would move the initializer to <clinit>, but
|
// Normally, `InitializersLowering` would move the initializer to <clinit>, but it's obviously too late for that.
|
||||||
// it's obviously too late for that.
|
val init = with(field) {
|
||||||
val init = IrSetFieldImpl(
|
IrSetFieldImpl(startOffset, endOffset, symbol, null, initializer!!.expression, context.irBuiltIns.unitType)
|
||||||
field.startOffset, field.endOffset, field.symbol, null,
|
}
|
||||||
field.initializer!!.expression, context.irBuiltIns.unitType
|
|
||||||
)
|
|
||||||
if (generatingClInit) {
|
if (generatingClInit) {
|
||||||
// Too late to modify the IR; have to ask the currently active `ExpressionCodegen`
|
// Too late to modify the IR; have to ask the currently active `ExpressionCodegen` to generate this statement
|
||||||
// to generate this statement directly.
|
// directly. At least we know that nothing before this point uses the field.
|
||||||
return init
|
return init
|
||||||
}
|
}
|
||||||
val classInitializer = irClass.functions.singleOrNull { it.name.asString() == "<clinit>" } ?: irClass.addFunction {
|
val classInitializer = irClass.functions.singleOrNull { it.name.asString() == "<clinit>" } ?: irClass.addFunction {
|
||||||
@@ -221,6 +218,7 @@ class ClassCodegen private constructor(
|
|||||||
}.apply {
|
}.apply {
|
||||||
body = IrBlockBodyImpl(startOffset, endOffset)
|
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)
|
(classInitializer.body as IrBlockBody).statements.add(0, init)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -46,13 +46,11 @@ class IrInlineCodegen(
|
|||||||
InlineCodegen<ExpressionCodegen>(codegen, state, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner),
|
InlineCodegen<ExpressionCodegen>(codegen, state, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner),
|
||||||
IrInlineCallGenerator {
|
IrInlineCallGenerator {
|
||||||
|
|
||||||
override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
|
override fun generateAssertField() {
|
||||||
if (info.generateAssertField) {
|
// May be inlining code into `<clinit>`, in which case it's too late to modify the IR and
|
||||||
// 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.
|
||||||
// `generateAssertFieldIfNeeded` will return a statement for which we need to emit bytecode.
|
val isClInit = sourceCompiler.inlineCallSiteInfo.method.name == "<clinit>"
|
||||||
val isClInit = info.callSiteInfo.method.name == "<clinit>"
|
codegen.classCodegen.generateAssertFieldIfNeeded(isClInit)?.accept(codegen, BlockInfo())?.discard()
|
||||||
codegen.classCodegen.generateAssertFieldIfNeeded(isClInit)?.accept(codegen, BlockInfo())?.discard()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun genValueAndPut(
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
+6
@@ -894,6 +894,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
+6
@@ -894,6 +894,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
+6
@@ -894,6 +894,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
+6
@@ -894,6 +894,12 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
|
|||||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
+6
@@ -894,6 +894,12 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
|
|||||||
runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt");
|
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
|
@Test
|
||||||
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
@TestMetadata("jvmInlineUsedAsNoinline.kt")
|
||||||
public void testJvmInlineUsedAsNoinline() throws Exception {
|
public void testJvmInlineUsedAsNoinline() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user