JVM: do not use crossinline flag when inlining assertions

Crossinline lambdas *can* be inlined into objects, but don't *have* to;
the correct place should be determined from the context, not from the
parameter.
This commit is contained in:
pyos
2021-07-06 10:57:48 +02:00
committed by max-kammerer
parent e64cda61d5
commit 50797dba8d
13 changed files with 191 additions and 27 deletions
@@ -1264,7 +1264,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
// Thus, do not generate it. Otherwise, it leads to VerifyError on run-time.
boolean isCrossinlineLambda = (callGenerator instanceof PsiInlineCodegen) &&
Objects.requireNonNull(((PsiInlineCodegen) callGenerator).getActiveLambda(),
"no active lambda found").isCrossInline;
"no active lambda found").isCrossInline();
if (!isCrossinlineLambda) {
v.aconst(null);
}
@@ -16,8 +16,7 @@ import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
interface FunctionalArgument
abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgument {
abstract class LambdaInfo : FunctionalArgument {
abstract val isBoundCallableReference: Boolean
abstract val isSuspend: Boolean
@@ -66,7 +65,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
object NonInlineableArgumentForInlineableParameterCalledInSuspend : FunctionalArgument
object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument
abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInline) {
abstract class ExpressionLambda : LambdaInfo() {
fun generateLambdaBody(sourceCompiler: SourceCompilerForInline) {
node = sourceCompiler.generateLambdaBody(this, reifiedTypeParametersUsages)
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
@@ -76,11 +75,10 @@ abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInli
abstract class DefaultLambda(
final override val lambdaClassType: Type,
capturedArgs: Array<Type>,
isCrossinline: Boolean,
val offset: Int,
val needReification: Boolean,
sourceCompiler: SourceCompilerForInline
) : LambdaInfo(isCrossinline) {
) : LambdaInfo() {
final override val isSuspend
get() = false // TODO: it should probably be true sometimes, but it never was
final override val isBoundCallableReference: Boolean
@@ -558,21 +558,17 @@ class MethodInliner(
)
} else if (fieldInsnNode.isCheckAssertionsStatus()) {
fieldInsnNode.owner = inlineCallSiteInfo.ownerClassName
if (inliningContext.isInliningLambda) {
if (inliningContext.lambdaInfo!!.isCrossInline) {
assert(inliningContext.parent?.parent is RegeneratedClassContext) {
"$inliningContext grandparent shall be RegeneratedClassContext but got ${inliningContext.parent?.parent}"
}
inliningContext.parent!!.parent!!.generateAssertField = true
} else {
assert(inliningContext.parent != null) {
"$inliningContext parent shall not be null"
}
inliningContext.parent!!.generateAssertField = true
}
} else {
inliningContext.generateAssertField = true
}
when {
// In inline function itself:
inliningContext.parent == null -> inliningContext
// In method of regenerated object - field should already exist:
inliningContext.parent is RegeneratedClassContext -> inliningContext.parent
// In lambda inlined into the root function:
inliningContext.parent.parent == null -> inliningContext.parent
// In lambda inlined into a method of a regenerated object:
else -> inliningContext.parent.parent as? RegeneratedClassContext
?: throw AssertionError("couldn't find class for \$assertionsDisabled (context = $inliningContext)")
}.generateAssertField = true
}
}
@@ -181,7 +181,7 @@ class PsiInlineCodegen(
}
}
var activeLambda: LambdaInfo? = null
var activeLambda: PsiExpressionLambda? = null
private set
private fun putClosureParametersOnStack(next: PsiExpressionLambda, receiverValue: StackValue?) {
@@ -210,9 +210,9 @@ private val FunctionDescriptor.explicitParameters
class PsiExpressionLambda(
expression: KtExpression,
private val state: GenerationState,
isCrossInline: Boolean,
val isCrossInline: Boolean,
override val isBoundCallableReference: Boolean
) : ExpressionLambda(isCrossInline) {
) : ExpressionLambda() {
override val lambdaClassType: Type
override val invokeMethod: Method
@@ -308,7 +308,7 @@ class PsiDefaultLambda(
offset: Int,
needReification: Boolean,
sourceCompiler: SourceCompilerForInline
) : DefaultLambda(lambdaClassType, capturedArgs, parameterDescriptor.isCrossinline, offset, needReification, sourceCompiler) {
) : DefaultLambda(lambdaClassType, capturedArgs, offset, needReification, sourceCompiler) {
private val invokeMethodDescriptor: FunctionDescriptor
override val invokeMethodParameters: List<KotlinType?>
@@ -882,6 +882,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {
@@ -133,7 +133,7 @@ class IrExpressionLambdaImpl(
codegen: ExpressionCodegen,
val reference: IrFunctionReference,
irValueParameter: IrValueParameter
) : ExpressionLambda(irValueParameter.isCrossinline), IrExpressionLambda {
) : ExpressionLambda(), IrExpressionLambda {
override val isExtensionLambda: Boolean = irValueParameter.type.isExtensionFunctionType
val function: IrFunction
@@ -194,7 +194,7 @@ class IrDefaultLambda(
offset: Int,
needReification: Boolean,
sourceCompiler: IrSourceCompilerForInline
) : DefaultLambda(lambdaClassType, capturedArgs, irValueParameter.isCrossinline, offset, needReification, sourceCompiler) {
) : DefaultLambda(lambdaClassType, capturedArgs, offset, needReification, sourceCompiler) {
private val typeArguments: MutableList<IrType>
@@ -0,0 +1,128 @@
// NO_CHECK_LAMBDA_INLINING
// WITH_RUNTIME
// TARGET_BACKEND: JVM
// ASSERTIONS_MODE: jvm
// FILE: inline.kt
package test
inline fun call(crossinline c: () -> Unit) {
c()
}
// FILE: inlineSite.kt
import test.*
interface Checker {
fun checkTrue(): Boolean
fun checkFalse(): Boolean
fun checkTrueWithMessage(): Boolean
fun checkFalseWithMessage(): Boolean
}
class ShouldBeDisabled : Checker {
override fun checkTrue(): Boolean {
var hit = false
val l = { hit = true; true }
call {
assert(l())
}
return hit
}
override fun checkFalse(): Boolean {
var hit = false
val l = { hit = true; false }
call {
assert(l())
}
return hit
}
override fun checkTrueWithMessage(): Boolean {
var hit = false
val l = { hit = true; true }
call {
assert(l()) { "BOOYA" }
}
return hit
}
override fun checkFalseWithMessage(): Boolean {
var hit = false
val l = { hit = true; false }
call {
assert(l()) { "BOOYA" }
}
return hit
}
}
class ShouldBeEnabled : Checker {
override fun checkTrue(): Boolean {
var hit = false
val l = { hit = true; true }
call {
assert(l())
}
return hit
}
override fun checkFalse(): Boolean {
var hit = false
val l = { hit = true; false }
call {
assert(l())
}
return hit
}
override fun checkTrueWithMessage(): Boolean {
var hit = false
val l = { hit = true; true }
call {
assert(l()) { "BOOYA" }
}
return hit
}
override fun checkFalseWithMessage(): Boolean {
var hit = false
val l = { hit = true; false }
call {
assert(l()) { "BOOYA" }
}
return hit
}
}
fun setDesiredAssertionStatus(v: Boolean): Checker {
val loader = Checker::class.java.classLoader
loader.setClassAssertionStatus("ShouldBeEnabled", true)
loader.setClassAssertionStatus("ShouldBeDisabled", false)
val c = loader.loadClass(if (v) "ShouldBeEnabled" else "ShouldBeDisabled")
return c.newInstance() as Checker
}
fun box(): String {
var c = setDesiredAssertionStatus(false)
if (c.checkTrue()) return "FAIL 0"
if (c.checkTrueWithMessage()) return "FAIL 1"
if (c.checkFalse()) return "FAIL 2"
if (c.checkFalseWithMessage()) return "FAIL 3"
c = setDesiredAssertionStatus(true)
if (!c.checkTrue()) return "FAIL 4"
if (!c.checkTrueWithMessage()) return "FAIL 5"
try {
c.checkFalse()
return "FAIL 6"
} catch (ignore: AssertionError) {
}
try {
c.checkFalseWithMessage()
return "FAIL 7"
} catch (ignore: AssertionError) {
}
return "OK"
}
@@ -882,6 +882,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {
@@ -882,6 +882,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {
@@ -882,6 +882,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {
@@ -882,6 +882,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {
@@ -882,6 +882,12 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {
@@ -882,6 +882,12 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSiteOnly.kt");
}
@Test
@TestMetadata("jvmCrossinlineRedundant.kt")
public void testJvmCrossinlineRedundant() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineRedundant.kt");
}
@Test
@TestMetadata("jvmCrossinlineSAMDeclarationSite.kt")
public void testJvmCrossinlineSAMDeclarationSite() throws Exception {