Put $assertionDisabled field into inline-site's class

The generated code is more inline with java, and we avoid the error of
accessing package-private field outside of the package.
However, this changes semantics a bit. Now, a user should set assertion
status of inline-site's package, instead of inline function's one.
 #KT-28317: Fixed
This commit is contained in:
Ilmir Usmanov
2019-02-01 20:11:06 +03:00
parent acb83f1af1
commit 1e4b7e1ef1
25 changed files with 818 additions and 33 deletions
@@ -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. * 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.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.org.objectweb.asm.Label 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.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode 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 ALWAYS_ENABLED_ASSERT_FUNCTION_NAME = "alwaysEnabledAssert"
private const val LAMBDA_INTERNAL_NAME = "kotlin/jvm/functions/Function0" private const val LAMBDA_INTERNAL_NAME = "kotlin/jvm/functions/Function0"
private const val ASSERTION_ERROR_INTERNAL_NAME = "java/lang/AssertionError" private const val ASSERTION_ERROR_INTERNAL_NAME = "java/lang/AssertionError"
@@ -43,6 +45,9 @@ private fun FunctionDescriptor.isBuiltinAlwaysEnabledAssertWithoutLambda() =
fun FunctionDescriptor.isBuiltinAlwaysEnabledAssert() = fun FunctionDescriptor.isBuiltinAlwaysEnabledAssert() =
this.isBuiltinAlwaysEnabledAssertWithLambda() || this.isBuiltinAlwaysEnabledAssertWithoutLambda() this.isBuiltinAlwaysEnabledAssertWithLambda() || this.isBuiltinAlwaysEnabledAssertWithoutLambda()
fun FieldInsnNode.isCheckAssertionsStatus() =
opcode == Opcodes.GETSTATIC && name == ASSERTIONS_DISABLED_FIELD_NAME && desc == Type.BOOLEAN_TYPE.descriptor
fun createMethodNodeForAlwaysEnabledAssert( fun createMethodNodeForAlwaysEnabledAssert(
functionDescriptor: FunctionDescriptor, functionDescriptor: FunctionDescriptor,
typeMapper: KotlinTypeMapper typeMapper: KotlinTypeMapper
@@ -131,17 +136,16 @@ private fun inlineAlwaysInlineAssert(resolvedCall: ResolvedCall<*>, codegen: Exp
) )
} }
fun generateAssertionsDisabledFieldInitialization(parentCodegen: MemberCodegen<*>) { fun generateAssertionsDisabledFieldInitialization(classBuilder: ClassBuilder, clInitBuilder: MethodVisitor) {
parentCodegen.v.newField( classBuilder.newField(
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC, assertionsDisabledFieldName, JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC or Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC, ASSERTIONS_DISABLED_FIELD_NAME,
"Z", null, null "Z", null, null
) )
val clInitCodegen = parentCodegen.createOrGetClInitCodegen()
MemberCodegen.markLineNumberForElement(parentCodegen.element.psiOrParent, clInitCodegen.v)
val thenLabel = Label() val thenLabel = Label()
val elseLabel = Label() val elseLabel = Label()
with(clInitCodegen.v) { with(InstructionAdapter(clInitBuilder)) {
aconst(Type.getObjectType(parentCodegen.v.thisName)) mark(Label())
aconst(Type.getObjectType(classBuilder.thisName))
invokevirtual("java/lang/Class", "desiredAssertionStatus", "()Z", false) invokevirtual("java/lang/Class", "desiredAssertionStatus", "()Z", false)
ifne(thenLabel) ifne(thenLabel)
iconst(1) iconst(1)
@@ -151,7 +155,7 @@ fun generateAssertionsDisabledFieldInitialization(parentCodegen: MemberCodegen<*
iconst(0) iconst(0)
mark(elseLabel) mark(elseLabel)
putstatic(parentCodegen.v.thisName, assertionsDisabledFieldName, "Z") putstatic(classBuilder.thisName, ASSERTIONS_DISABLED_FIELD_NAME, "Z")
} }
} }
@@ -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. * that can be found in the license/LICENSE.txt file.
*/ */
@@ -922,7 +922,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
public void generateAssertField() { public void generateAssertField() {
if (jvmAssertFieldGenerated) return; if (jvmAssertFieldGenerated) return;
AssertCodegenUtilKt.generateAssertionsDisabledFieldInitialization(this); AssertCodegenUtilKt.generateAssertionsDisabledFieldInitialization(v, createOrGetClInitCodegen().v);
jvmAssertFieldGenerated = true; jvmAssertFieldGenerated = true;
} }
@@ -1,18 +1,15 @@
/* /*
* 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. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
import org.jetbrains.kotlin.codegen.writeKotlinMetadata
import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -179,6 +176,13 @@ class AnonymousObjectTransformer(
writeOuterInfo(visitor) writeOuterInfo(visitor)
if (inliningContext.generateAssertField && fieldNames.none { it.key == ASSERTIONS_DISABLED_FIELD_NAME }) {
val clInitBuilder = classBuilder.newMethod(NO_ORIGIN, Opcodes.ACC_STATIC, "<clinit>", "()V", null, null)
generateAssertionsDisabledFieldInitialization(classBuilder, clInitBuilder)
clInitBuilder.visitInsn(Opcodes.RETURN)
clInitBuilder.visitEnd()
}
if (continuationClassName == transformationInfo.oldClassName) { if (continuationClassName == transformationInfo.oldClassName) {
coroutineTransformer.registerClassBuilder(continuationClassName) coroutineTransformer.registerClassBuilder(continuationClassName)
} else { } else {
@@ -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. * that can be found in the license/LICENSE.txt file.
*/ */
@@ -299,9 +299,13 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
defaultSourceMapper.callSiteMarker = null defaultSourceMapper.callSiteMarker = null
generateAssertFieldIfNeeded(info)
return result return result
} }
protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext)
private fun isInlinedToInlineFunInKotlinRuntime(): Boolean { private fun isInlinedToInlineFunInKotlinRuntime(): Boolean {
val codegen = this.codegen as? ExpressionCodegen ?: return false val codegen = this.codegen as? ExpressionCodegen ?: return false
val caller = codegen.context.functionDescriptor val caller = codegen.context.functionDescriptor
@@ -661,6 +665,12 @@ class PsiInlineCodegen(
sourceCompiler: SourceCompilerForInline sourceCompiler: SourceCompilerForInline
) : InlineCodegen<ExpressionCodegen>(codegen, state, function, typeParameterMappings, sourceCompiler), CallGenerator { ) : InlineCodegen<ExpressionCodegen>(codegen, state, function, typeParameterMappings, sourceCompiler), CallGenerator {
override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
if (info.generateAssertField) {
codegen.parentCodegen.generateAssertField()
}
}
override fun genCallInner( override fun genCallInner(
callableMethod: Callable, callableMethod: Callable,
resolvedCall: ResolvedCall<*>?, resolvedCall: ResolvedCall<*>?,
@@ -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. * that can be found in the license/LICENSE.txt file.
*/ */
@@ -46,6 +46,8 @@ open class InliningContext(
val isInliningLambda = lambdaInfo != null val isInliningLambda = lambdaInfo != null
var generateAssertField = false
private val internalNameToAnonymousObjectTransformationInfo = hashMapOf<String, AnonymousObjectTransformationInfo>() private val internalNameToAnonymousObjectTransformationInfo = hashMapOf<String, AnonymousObjectTransformationInfo>()
var isContinuation: Boolean = false var isContinuation: Boolean = false
@@ -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. * that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.ClosureCodegen
import org.jetbrains.kotlin.codegen.IrExpressionLambda
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
@@ -578,6 +575,23 @@ class MethodInliner(
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode 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
}
} }
} }
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.codegen.inline
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
import org.jetbrains.kotlin.codegen.binding.CodegenBinding 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 { internal fun isCapturedFieldName(fieldName: String): Boolean {
// TODO: improve this heuristic // TODO: improve this heuristic
return fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX) return fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX)
&& fieldName != ASSERTIONS_DISABLED_FIELD_NAME
|| AsmUtil.CAPTURED_THIS_FIELD == fieldName || AsmUtil.CAPTURED_THIS_FIELD == fieldName
|| AsmUtil.CAPTURED_RECEIVER_FIELD == fieldName || AsmUtil.CAPTURED_RECEIVER_FIELD == fieldName
} }
@@ -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. * that can be found in the license/LICENSE.txt file.
*/ */
@@ -27,6 +27,9 @@ class IrInlineCodegen(
typeParameterMappings: TypeParameterMappings, typeParameterMappings: TypeParameterMappings,
sourceCompiler: SourceCompilerForInline sourceCompiler: SourceCompilerForInline
) : InlineCodegen<ExpressionCodegen>(codegen, state, function, typeParameterMappings, sourceCompiler), IrCallGenerator { ) : InlineCodegen<ExpressionCodegen>(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?) { override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) {
val lambdaInfo = next as IrExpressionLambdaImpl val lambdaInfo = next as IrExpressionLambdaImpl
@@ -5,6 +5,8 @@
// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
package test
inline fun inlineMe() { inline fun inlineMe() {
assert(false) { "FROM INLINED" } assert(false) { "FROM INLINED" }
} }
@@ -12,6 +14,8 @@ inline fun inlineMe() {
// FILE: inlineSite.kt // FILE: inlineSite.kt
// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm
import test.*
class CheckerJvmAssertInlineFunctionAssertionsDisabled { class CheckerJvmAssertInlineFunctionAssertionsDisabled {
fun check() { fun check() {
inlineMe() inlineMe()
@@ -3,6 +3,8 @@
// WITH_RUNTIME // WITH_RUNTIME
// FULL_JDK // FULL_JDK
package test
inline fun inlineMe() { inline fun inlineMe() {
assert(false) { "FROM INLINED" } assert(false) { "FROM INLINED" }
} }
@@ -10,6 +12,8 @@ inline fun inlineMe() {
// FILE: inlineSite.kt // FILE: inlineSite.kt
// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm
import test.*
class CheckerJvmAssertInlineFunctionAssertionsEnabled { class CheckerJvmAssertInlineFunctionAssertionsEnabled {
fun check() { fun check() {
inlineMe() inlineMe()
@@ -5,6 +5,8 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
package test
inline fun call(c: () -> Unit) { inline fun call(c: () -> Unit) {
c() c()
} }
@@ -12,6 +14,8 @@ inline fun call(c: () -> Unit) {
// FILE: inlineSite.kt // FILE: inlineSite.kt
// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm
import test.*
interface Checker { interface Checker {
fun checkTrue(): Boolean fun checkTrue(): Boolean
fun checkFalse(): Boolean fun checkFalse(): Boolean
@@ -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
}
@@ -5,6 +5,8 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
package test
object CrossinlineLambdaContainer { object CrossinlineLambdaContainer {
inline fun call(crossinline c: () -> Unit) { inline fun call(crossinline c: () -> Unit) {
val l = { c() } val l = { c() }
@@ -15,7 +17,7 @@ object CrossinlineLambdaContainer {
// FILE: inlineSite.kt // FILE: inlineSite.kt
// KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm // KOTLIN_CONFIGURATION_FLAGS: ASSERTIONS_MODE=jvm
import CrossinlineLambdaContainer.call import test.CrossinlineLambdaContainer.call
interface Checker { interface Checker {
fun checkTrue(): Boolean fun checkTrue(): Boolean
@@ -102,9 +104,7 @@ class ShouldBeEnabled : Checker {
fun setDesiredAssertionStatus(v: Boolean): Checker { fun setDesiredAssertionStatus(v: Boolean): Checker {
val loader = Checker::class.java.classLoader val loader = Checker::class.java.classLoader
loader.setClassAssertionStatus("ShouldBeEnabled", true) loader.setDefaultAssertionStatus(v)
loader.setClassAssertionStatus("ShouldBeDisabled", false)
loader.setClassAssertionStatus("CrossinlineLambdaContainer", v)
val c = loader.loadClass(if (v) "ShouldBeEnabled" else "ShouldBeDisabled") val c = loader.loadClass(if (v) "ShouldBeEnabled" else "ShouldBeDisabled")
return c.newInstance() as Checker return c.newInstance() as Checker
} }
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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
@@ -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.<clinit>:
// 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
@@ -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.<clinit>:
// 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
@@ -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
@@ -640,10 +640,30 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt"); 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") @TestMetadata("jvmCrossinlineLambda.kt")
public void testJvmCrossinlineLambda() throws Exception { public void testJvmCrossinlineLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt"); 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") @TestMetadata("compiler/testData/codegen/boxInline/builders")
@@ -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") @TestMetadata("compiler/testData/codegen/bytecodeText/boxing")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -640,10 +640,30 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt"); 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") @TestMetadata("jvmCrossinlineLambda.kt")
public void testJvmCrossinlineLambda() throws Exception { public void testJvmCrossinlineLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt"); 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") @TestMetadata("compiler/testData/codegen/boxInline/builders")
@@ -640,10 +640,30 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/assert/jvmAssertInlineLambda.kt"); 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") @TestMetadata("jvmCrossinlineLambda.kt")
public void testJvmCrossinlineLambda() throws Exception { public void testJvmCrossinlineLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/assert/jvmCrossinlineLambda.kt"); 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") @TestMetadata("compiler/testData/codegen/boxInline/builders")
@@ -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") @TestMetadata("compiler/testData/codegen/bytecodeText/boxing")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)