diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AssertCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/AssertCodegenUtil.kt index 4c0f4c4fa13..b693c821a26 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AssertCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AssertCodegenUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -21,12 +21,14 @@ import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode import org.jetbrains.org.objectweb.asm.tree.MethodNode -val assertionsDisabledFieldName = "\$assertionsDisabled" +const val ASSERTIONS_DISABLED_FIELD_NAME = "\$assertionsDisabled" private const val ALWAYS_ENABLED_ASSERT_FUNCTION_NAME = "alwaysEnabledAssert" private const val LAMBDA_INTERNAL_NAME = "kotlin/jvm/functions/Function0" private const val ASSERTION_ERROR_INTERNAL_NAME = "java/lang/AssertionError" @@ -43,6 +45,9 @@ private fun FunctionDescriptor.isBuiltinAlwaysEnabledAssertWithoutLambda() = fun FunctionDescriptor.isBuiltinAlwaysEnabledAssert() = this.isBuiltinAlwaysEnabledAssertWithLambda() || this.isBuiltinAlwaysEnabledAssertWithoutLambda() +fun FieldInsnNode.isCheckAssertionsStatus() = + opcode == Opcodes.GETSTATIC && name == ASSERTIONS_DISABLED_FIELD_NAME && desc == Type.BOOLEAN_TYPE.descriptor + fun createMethodNodeForAlwaysEnabledAssert( functionDescriptor: FunctionDescriptor, typeMapper: KotlinTypeMapper @@ -131,17 +136,16 @@ private fun inlineAlwaysInlineAssert(resolvedCall: ResolvedCall<*>, codegen: Exp ) } -fun generateAssertionsDisabledFieldInitialization(parentCodegen: MemberCodegen<*>) { - parentCodegen.v.newField( - JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC, assertionsDisabledFieldName, +fun generateAssertionsDisabledFieldInitialization(classBuilder: ClassBuilder, clInitBuilder: MethodVisitor) { + classBuilder.newField( + JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC, ASSERTIONS_DISABLED_FIELD_NAME, "Z", null, null ) - val clInitCodegen = parentCodegen.createOrGetClInitCodegen() - MemberCodegen.markLineNumberForElement(parentCodegen.element.psiOrParent, clInitCodegen.v) val thenLabel = Label() val elseLabel = Label() - with(clInitCodegen.v) { - aconst(Type.getObjectType(parentCodegen.v.thisName)) + with(InstructionAdapter(clInitBuilder)) { + mark(Label()) + aconst(Type.getObjectType(classBuilder.thisName)) invokevirtual("java/lang/Class", "desiredAssertionStatus", "()Z", false) ifne(thenLabel) iconst(1) @@ -151,7 +155,7 @@ fun generateAssertionsDisabledFieldInitialization(parentCodegen: MemberCodegen<* iconst(0) mark(elseLabel) - putstatic(parentCodegen.v.thisName, assertionsDisabledFieldName, "Z") + putstatic(classBuilder.thisName, ASSERTIONS_DISABLED_FIELD_NAME, "Z") } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index eedf6daab82..a5005ae1e85 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -922,7 +922,7 @@ public abstract class MemberCodegen", "()V", null, null) + generateAssertionsDisabledFieldInitialization(classBuilder, clInitBuilder) + clInitBuilder.visitInsn(Opcodes.RETURN) + clInitBuilder.visitEnd() + } + if (continuationClassName == transformationInfo.oldClassName) { coroutineTransformer.registerClassBuilder(continuationClassName) } else { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 606abcdf958..9f0afff50ab 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -299,9 +299,13 @@ abstract class InlineCodegen( defaultSourceMapper.callSiteMarker = null + generateAssertFieldIfNeeded(info) + return result } + protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext) + private fun isInlinedToInlineFunInKotlinRuntime(): Boolean { val codegen = this.codegen as? ExpressionCodegen ?: return false val caller = codegen.context.functionDescriptor @@ -661,6 +665,12 @@ class PsiInlineCodegen( sourceCompiler: SourceCompilerForInline ) : InlineCodegen(codegen, state, function, typeParameterMappings, sourceCompiler), CallGenerator { + override fun generateAssertFieldIfNeeded(info: RootInliningContext) { + if (info.generateAssertField) { + codegen.parentCodegen.generateAssertField() + } + } + override fun genCallInner( callableMethod: Callable, resolvedCall: ResolvedCall<*>?, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt index fb0749a5ee1..afa4b20521a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -46,6 +46,8 @@ open class InliningContext( val isInliningLambda = lambdaInfo != null + var generateAssertField = false + private val internalNameToAnonymousObjectTransformationInfo = hashMapOf() var isContinuation: Boolean = false diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index f655b1f95b8..8031851df82 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -1,14 +1,11 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. 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.codegen.inline -import org.jetbrains.kotlin.codegen.AsmUtil -import org.jetbrains.kotlin.codegen.ClosureCodegen -import org.jetbrains.kotlin.codegen.IrExpressionLambda -import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName @@ -578,6 +575,23 @@ class MethodInliner( className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode ) ) + } 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 + } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index b5581814ef6..e32e25c16c3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -7,10 +7,7 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.codegen.AsmUtil -import org.jetbrains.kotlin.codegen.BaseExpressionCodegen -import org.jetbrains.kotlin.codegen.ExpressionCodegen -import org.jetbrains.kotlin.codegen.JvmCodegenUtil +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping import org.jetbrains.kotlin.codegen.binding.CodegenBinding @@ -258,6 +255,7 @@ private fun String.isInteger(radix: Int = 10) = toIntOrNull(radix) != null internal fun isCapturedFieldName(fieldName: String): Boolean { // TODO: improve this heuristic return fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX) + && fieldName != ASSERTIONS_DISABLED_FIELD_NAME || AsmUtil.CAPTURED_THIS_FIELD == fieldName || AsmUtil.CAPTURED_RECEIVER_FIELD == fieldName } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 12130e3a21d..b4dbb442f98 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -27,6 +27,9 @@ class IrInlineCodegen( typeParameterMappings: TypeParameterMappings, sourceCompiler: SourceCompilerForInline ) : InlineCodegen(codegen, state, function, typeParameterMappings, sourceCompiler), IrCallGenerator { + override fun generateAssertFieldIfNeeded(info: RootInliningContext) { + // TODO: JVM assertions are not implemented yet in IR backend + } override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { val lambdaInfo = next as IrExpressionLambdaImpl diff --git a/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsDisabled.kt b/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsDisabled.kt index 1eb8c9f74b2..3db4c050527 100644 --- a/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsDisabled.kt +++ b/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsDisabled.kt @@ -5,6 +5,8 @@ // IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM +package test + inline fun inlineMe() { assert(false) { "FROM INLINED" } } @@ -12,6 +14,8 @@ inline fun inlineMe() { // FILE: inlineSite.kt // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +import test.* + class CheckerJvmAssertInlineFunctionAssertionsDisabled { fun check() { inlineMe() diff --git a/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsEnabled.kt b/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsEnabled.kt index b970dd206c4..023594d2059 100644 --- a/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsEnabled.kt +++ b/compiler/testData/codegen/boxInline/assert/jvmAssertInlineFunctionAssertionsEnabled.kt @@ -3,6 +3,8 @@ // WITH_RUNTIME // FULL_JDK +package test + inline fun inlineMe() { assert(false) { "FROM INLINED" } } @@ -10,6 +12,8 @@ inline fun inlineMe() { // FILE: inlineSite.kt // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +import test.* + class CheckerJvmAssertInlineFunctionAssertionsEnabled { fun check() { inlineMe() diff --git a/compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt b/compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt index 9231fd9c331..d8d3925a350 100644 --- a/compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt +++ b/compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt @@ -5,6 +5,8 @@ // WITH_RUNTIME // NO_CHECK_LAMBDA_INLINING +package test + inline fun call(c: () -> Unit) { c() } @@ -12,6 +14,8 @@ inline fun call(c: () -> Unit) { // FILE: inlineSite.kt // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +import test.* + interface Checker { fun checkTrue(): Boolean fun checkFalse(): Boolean diff --git a/compiler/testData/codegen/boxInline/assert/jvmCompanion.kt b/compiler/testData/codegen/boxInline/assert/jvmCompanion.kt new file mode 100644 index 00000000000..666681aeffe --- /dev/null +++ b/compiler/testData/codegen/boxInline/assert/jvmCompanion.kt @@ -0,0 +1,46 @@ +// TARGET_BACKEND: JVM +// FILE: inline.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +// WITH_RUNTIME +// FULL_JDK +package test + +var result = "OK" + +class State { + + companion object { + inline fun inlineMe() { + assert(false) { "FROM INLINED" } + } + } +} + +// FILE: inlineSite.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +import test.* + +class CheckerJvmAssertInlineFunctionAssertionsEnabled { + fun check() { + State.inlineMe() + throw RuntimeException("FAIL 0") + } +} + +class Dummy + +fun enableAssertions(): CheckerJvmAssertInlineFunctionAssertionsEnabled { + val loader = Dummy::class.java.classLoader + loader.setDefaultAssertionStatus(true) + val c = loader.loadClass("CheckerJvmAssertInlineFunctionAssertionsEnabled") + return c.newInstance() as CheckerJvmAssertInlineFunctionAssertionsEnabled +} + +fun box(): String { + var c = enableAssertions() + try { + c.check() + return "FAIL 2" + } catch (ignore: AssertionError) {} + return result +} diff --git a/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt b/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt index caeec96ffa8..8d0fb45daf8 100644 --- a/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt +++ b/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt @@ -5,6 +5,8 @@ // WITH_RUNTIME // NO_CHECK_LAMBDA_INLINING +package test + object CrossinlineLambdaContainer { inline fun call(crossinline c: () -> Unit) { val l = { c() } @@ -15,7 +17,7 @@ object CrossinlineLambdaContainer { // FILE: inlineSite.kt // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm -import CrossinlineLambdaContainer.call +import test.CrossinlineLambdaContainer.call interface Checker { fun checkTrue(): Boolean @@ -102,9 +104,7 @@ class ShouldBeEnabled : Checker { fun setDesiredAssertionStatus(v: Boolean): Checker { val loader = Checker::class.java.classLoader - loader.setClassAssertionStatus("ShouldBeEnabled", true) - loader.setClassAssertionStatus("ShouldBeDisabled", false) - loader.setClassAssertionStatus("CrossinlineLambdaContainer", v) + loader.setDefaultAssertionStatus(v) val c = loader.loadClass(if (v) "ShouldBeEnabled" else "ShouldBeDisabled") return c.newInstance() as Checker } diff --git a/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda2.kt b/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda2.kt new file mode 100644 index 00000000000..788907104c2 --- /dev/null +++ b/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda2.kt @@ -0,0 +1,237 @@ +// IGNORE_BACKEND: JVM_IR +// TARGET_BACKEND: JVM +// FILE: inline.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +// WITH_RUNTIME +// NO_CHECK_LAMBDA_INLINING + +package test + +object CrossinlineLambdaContainer { + inline fun call(b: Boolean, crossinline c: () -> Unit) { + val l = { + assert(b) { "FROM INLINED" } + c() + } + l() + } +} + +// FILE: inlineSite.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm + +import test.CrossinlineLambdaContainer.call + +interface Checker { + fun checkTrueTrue(): Boolean + fun checkTrueFalse(): Boolean + fun checkFalseTrue(): Boolean + fun checkFalseFalse(): Boolean + fun checkTrueWithMessageTrue(): Boolean + fun checkTrueWithMessageFalse(): Boolean + fun checkFalseWithMessageTrue(): Boolean + fun checkFalseWithMessageFalse(): Boolean +} + +class ShouldBeDisabled : Checker { + override fun checkTrueTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) + } + return hit + } + + override fun checkTrueFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) + } + return hit + } + + override fun checkFalseTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) + } + return hit + } + + override fun checkFalseFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) + } + return hit + } + + override fun checkTrueWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkTrueWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } +} + +class ShouldBeEnabled : Checker { + override fun checkTrueTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) + } + return hit + } + + override fun checkTrueFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) + } + return hit + } + + override fun checkFalseTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) + } + return hit + } + + override fun checkFalseFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) + } + return hit + } + + override fun checkTrueWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkTrueWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } +} + +fun setDesiredAssertionStatus(v: Boolean): Checker { + val loader = Checker::class.java.classLoader + loader.setDefaultAssertionStatus(v) + val c = loader.loadClass(if (v) "ShouldBeEnabled" else "ShouldBeDisabled") + return c.newInstance() as Checker +} + +fun box(): String { + var c = setDesiredAssertionStatus(false) + if (c.checkTrueTrue()) return "FAIL 00" + if (c.checkTrueFalse()) return "FAIL 01" + if (c.checkTrueWithMessageTrue()) return "FAIL 10" + if (c.checkTrueWithMessageFalse()) return "FAIL 11" + if (c.checkFalseTrue()) return "FAIL 20" + if (c.checkFalseFalse()) return "FAIL 21" + if (c.checkFalseWithMessageTrue()) return "FAIL 30" + if (c.checkFalseWithMessageFalse()) return "FAIL 31" + + c = setDesiredAssertionStatus(true) + if (!c.checkTrueTrue()) return "FAIL 40" + try { + c.checkTrueFalse() + return "FAIL 41" + } catch (ignore: AssertionError) { + } + if (!c.checkTrueWithMessageTrue()) return "FAIL 50" + try { + c.checkTrueWithMessageFalse() + return "FAIL 51" + } catch (ignore: AssertionError) { + } + try { + c.checkFalseTrue() + return "FAIL 60" + } catch (ignore: AssertionError) { + } + try { + c.checkFalseFalse() + return "FAIL 61" + } catch (ignore: AssertionError) { + } + try { + c.checkFalseWithMessageTrue() + return "FAIL 70" + } catch (ignore: AssertionError) { + } + try { + c.checkFalseWithMessageFalse() + return "FAIL 71" + } catch (ignore: AssertionError) { + } + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSite.kt b/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSite.kt new file mode 100644 index 00000000000..153786f25fd --- /dev/null +++ b/compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSite.kt @@ -0,0 +1,214 @@ +// IGNORE_BACKEND: JVM_IR +// TARGET_BACKEND: JVM +// FILE: inline.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +// WITH_RUNTIME +// NO_CHECK_LAMBDA_INLINING + +package test + +object CrossinlineLambdaContainer { + inline fun call(b: Boolean, crossinline c: () -> Unit) { + val l = { + assert(b) { "FROM INLINED" } + c() + } + l() + } +} + +// FILE: inlineSite.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm + +import test.CrossinlineLambdaContainer.call + +interface Checker { + fun checkTrueTrue(): Boolean + fun checkTrueFalse(): Boolean + fun checkFalseTrue(): Boolean + fun checkFalseFalse(): Boolean + fun checkTrueWithMessageTrue(): Boolean + fun checkTrueWithMessageFalse(): Boolean + fun checkFalseWithMessageTrue(): Boolean + fun checkFalseWithMessageFalse(): Boolean +} + +class ShouldBeDisabled : Checker { + override fun checkTrueTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) + } + return hit + } + + override fun checkTrueFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) + } + return hit + } + + override fun checkFalseTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) + } + return hit + } + + override fun checkFalseFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) + } + return hit + } + + override fun checkTrueWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkTrueWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } +} + +class ShouldBeEnabled : Checker { + override fun checkTrueTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) + } + return hit + } + + override fun checkTrueFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) + } + return hit + } + + override fun checkFalseTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) + } + return hit + } + + override fun checkFalseFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) + } + return hit + } + + override fun checkTrueWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; true } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkTrueWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; true } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageTrue(): Boolean { + var hit = false + val l = { hit = true; false } + call(true) { + assert(l()) { "BOOYA" } + } + return hit + } + + override fun checkFalseWithMessageFalse(): Boolean { + var hit = false + val l = { hit = true; false } + call(false) { + assert(l()) { "BOOYA" } + } + return hit + } +} + +fun setDesiredAssertionStatus(v: Boolean): Checker { + val loader = Checker::class.java.classLoader + loader.setDefaultAssertionStatus(false) + loader.setPackageAssertionStatus("test", v) + val c = loader.loadClass(if (v) "ShouldBeEnabled" else "ShouldBeDisabled") + return c.newInstance() as Checker +} + +fun box(): String { + var c = setDesiredAssertionStatus(false) + if (c.checkTrueTrue()) return "FAIL 00" + if (c.checkTrueFalse()) return "FAIL 01" + if (c.checkTrueWithMessageTrue()) return "FAIL 10" + if (c.checkTrueWithMessageFalse()) return "FAIL 11" + if (c.checkFalseTrue()) return "FAIL 20" + if (c.checkFalseFalse()) return "FAIL 21" + if (c.checkFalseWithMessageTrue()) return "FAIL 30" + if (c.checkFalseWithMessageFalse()) return "FAIL 31" + + c = setDesiredAssertionStatus(true) + if (c.checkTrueTrue()) return "FAIL 100" + if (c.checkTrueFalse()) return "FAIL 101" + if (c.checkTrueWithMessageTrue()) return "FAIL 110" + if (c.checkTrueWithMessageFalse()) return "FAIL 111" + if (c.checkFalseTrue()) return "FAIL 120" + if (c.checkFalseFalse()) return "FAIL 121" + if (c.checkFalseWithMessageTrue()) return "FAIL 130" + if (c.checkFalseWithMessageFalse()) return "FAIL 131" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt b/compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt new file mode 100644 index 00000000000..649e1f76645 --- /dev/null +++ b/compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt @@ -0,0 +1,48 @@ +// TARGET_BACKEND: JVM +// FILE: inline.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +// WITH_RUNTIME +// FULL_JDK +package test + +class A { + inline fun a() { + assert(false) { "from inlined" } + } +} + +class B { + inline fun b() { + A().a() + error("FAIL 0") + } +} + +// FILE: inlineSite.kt +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm +import test.* + +class Checker { + fun check() { + B().b() + error("FAIL 1") + } +} + +class Dummy + +fun enableAssertions(): Checker { + val loader = Dummy::class.java.classLoader + loader.setDefaultAssertionStatus(true) + val c = loader.loadClass("Checker") + return c.newInstance() as Checker +} + +fun box(): String { + var c = enableAssertions() + try { + c.check() + return "FAIL 2" + } catch (ignore: AssertionError) {} + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/assert/jvmCrossinline.kt b/compiler/testData/codegen/bytecodeText/assert/jvmCrossinline.kt new file mode 100644 index 00000000000..e3b6cd36f92 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/assert/jvmCrossinline.kt @@ -0,0 +1,14 @@ +// IGNORE_BACKEND: JVM_IR +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm + +inline fun inlineMe(crossinline c : () -> Unit) = { c() } + +class A { + fun inlineSite() { + inlineMe { + assert(true) + } + } +} + +// 1 GETSTATIC A\$inlineSite\$\$inlined\$inlineMe\$1.\$assertionsDisabled diff --git a/compiler/testData/codegen/bytecodeText/assert/jvmCrossinlineAssertInLambda.kt b/compiler/testData/codegen/bytecodeText/assert/jvmCrossinlineAssertInLambda.kt new file mode 100644 index 00000000000..3bd5195bf4f --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/assert/jvmCrossinlineAssertInLambda.kt @@ -0,0 +1,21 @@ +// IGNORE_BACKEND: JVM_IR +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm + +inline fun inlineMe(crossinline c : () -> Unit) = { + assert(true) + c() +} + +class A { + fun inlineSite() { + inlineMe { } + } +} + +// inlineSite: +// 1 GETSTATIC A\$inlineSite\$\$inlined\$inlineMe\$1.\$assertionsDisabled +// A.: +// 1 LDC LA\$inlineSite\$\$inlined\$inlineMe\$1;.class\s*INVOKEVIRTUAL java/lang/Class.desiredAssertionStatus \(\)Z +// 1 PUTSTATIC A\$inlineSite\$\$inlined\$inlineMe\$1.\$assertionsDisabled : Z +// in declaration site and in inline site +// 2 INVOKEVIRTUAL java/lang/Class.desiredAssertionStatus \(\)Z diff --git a/compiler/testData/codegen/bytecodeText/assert/jvmInline.kt b/compiler/testData/codegen/bytecodeText/assert/jvmInline.kt new file mode 100644 index 00000000000..c7d7530a57a --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/assert/jvmInline.kt @@ -0,0 +1,18 @@ +// IGNORE_BACKEND: JVM_IR +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm + +inline fun inlineMe() = assert(true) + +class A { + fun inlineSite() { + inlineMe() + } +} + +// A.inlineSite: +// 1 GETSTATIC A.\$assertionsDisabled +// A.: +// 1 LDC LA;.class\s*INVOKEVIRTUAL java/lang/Class.desiredAssertionStatus \(\)Z +// 1 PUTSTATIC A.\$assertionsDisabled : Z +// in declaration site and in inline site +// 2 INVOKEVIRTUAL java/lang/Class.desiredAssertionStatus \(\)Z diff --git a/compiler/testData/codegen/bytecodeText/assert/jvmInlineLambda.kt b/compiler/testData/codegen/bytecodeText/assert/jvmInlineLambda.kt new file mode 100644 index 00000000000..e76d48714e4 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/assert/jvmInlineLambda.kt @@ -0,0 +1,14 @@ +// IGNORE_BACKEND: JVM_IR +// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm + +inline fun inlineMe(c: () -> Unit) = c() + +class A { + fun inlineSite() { + inlineMe { + assert(true) + } + } +} + +// 1 GETSTATIC A.\$assertionsDisabled diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 47d63535b50..beb337b3900 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -640,10 +640,30 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTest("compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt"); } + @TestMetadata("jvmCompanion.kt") + public void testJvmCompanion() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCompanion.kt"); + } + @TestMetadata("jvmCrossinlineLambda.kt") public void testJvmCrossinlineLambda() throws Exception { runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt"); } + + @TestMetadata("jvmCrossinlineLambda2.kt") + public void testJvmCrossinlineLambda2() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda2.kt"); + } + + @TestMetadata("jvmCrossinlineLambdaDeclarationSite.kt") + public void testJvmCrossinlineLambdaDeclarationSite() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSite.kt"); + } + + @TestMetadata("jvmDoubleInline.kt") + public void testJvmDoubleInline() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/builders") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 267f8fa4754..a33082f182f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -402,6 +402,39 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/assert") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Assert extends AbstractBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInAssert() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/assert"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("jvmCrossinline.kt") + public void testJvmCrossinline() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmCrossinline.kt"); + } + + @TestMetadata("jvmCrossinlineAssertInLambda.kt") + public void testJvmCrossinlineAssertInLambda() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmCrossinlineAssertInLambda.kt"); + } + + @TestMetadata("jvmInline.kt") + public void testJvmInline() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmInline.kt"); + } + + @TestMetadata("jvmInlineLambda.kt") + public void testJvmInlineLambda() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmInlineLambda.kt"); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/boxing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 5b19fbc1a43..57055182b32 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -640,10 +640,30 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTest("compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt"); } + @TestMetadata("jvmCompanion.kt") + public void testJvmCompanion() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCompanion.kt"); + } + @TestMetadata("jvmCrossinlineLambda.kt") public void testJvmCrossinlineLambda() throws Exception { runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt"); } + + @TestMetadata("jvmCrossinlineLambda2.kt") + public void testJvmCrossinlineLambda2() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda2.kt"); + } + + @TestMetadata("jvmCrossinlineLambdaDeclarationSite.kt") + public void testJvmCrossinlineLambdaDeclarationSite() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSite.kt"); + } + + @TestMetadata("jvmDoubleInline.kt") + public void testJvmDoubleInline() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/builders") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 2fb953242d2..5885b32b84c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -640,10 +640,30 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTest("compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt"); } + @TestMetadata("jvmCompanion.kt") + public void testJvmCompanion() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCompanion.kt"); + } + @TestMetadata("jvmCrossinlineLambda.kt") public void testJvmCrossinlineLambda() throws Exception { runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt"); } + + @TestMetadata("jvmCrossinlineLambda2.kt") + public void testJvmCrossinlineLambda2() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda2.kt"); + } + + @TestMetadata("jvmCrossinlineLambdaDeclarationSite.kt") + public void testJvmCrossinlineLambdaDeclarationSite() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambdaDeclarationSite.kt"); + } + + @TestMetadata("jvmDoubleInline.kt") + public void testJvmDoubleInline() throws Exception { + runTest("compiler/testData/codegen/boxInline/assert/jvmDoubleInline.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/builders") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index e32a022c7aa..e1a03441e3d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -402,6 +402,39 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/assert") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Assert extends AbstractIrBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInAssert() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/assert"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); + } + + @TestMetadata("jvmCrossinline.kt") + public void testJvmCrossinline() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmCrossinline.kt"); + } + + @TestMetadata("jvmCrossinlineAssertInLambda.kt") + public void testJvmCrossinlineAssertInLambda() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmCrossinlineAssertInLambda.kt"); + } + + @TestMetadata("jvmInline.kt") + public void testJvmInline() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmInline.kt"); + } + + @TestMetadata("jvmInlineLambda.kt") + public void testJvmInlineLambda() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/assert/jvmInlineLambda.kt"); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/boxing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)