Generate separate methods for inline and noinline uses of inline suspend functions

Previously, inline suspend functions were effectively inline only,
but ordinary inline functions can be used as noinline.
To fix the issue, I generate two functions: one for inline with suffix
$$forInline and without state machine; and the other one without any
suffix and state machine for direct calls.
This change does not affect effectively inline only suspend functions,
i.e. functions with reified generics, annotated with @InlineOnly
annotation and functions with crossinline parameters.
 #KT-20219: Fixed
This commit is contained in:
Ilmir Usmanov
2018-04-04 22:30:30 +03:00
parent bb4972b00e
commit 8a5ae16947
22 changed files with 528 additions and 82 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.JvmDefaultMode;
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
@@ -126,16 +128,28 @@ public class FunctionCodegen {
if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
FunctionGenerationStrategy strategy;
if (functionDescriptor.isSuspend() && !functionDescriptor.isInline()) {
strategy = new SuspendFunctionGenerationStrategy(
state,
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
function,
v.getThisName(),
state.getConstructorCallNormalizationMode()
);
}
else {
if (functionDescriptor.isSuspend()) {
if (AnnotationUtilKt.isEffectivelyInlineOnly(functionDescriptor)) {
strategy = new FunctionGenerationStrategy.FunctionDefault(state, function);
} else if (!functionDescriptor.isInline()) {
strategy = new SuspendFunctionGenerationStrategy(
state,
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
function,
v.getThisName(),
state.getConstructorCallNormalizationMode()
);
} else {
strategy = new SuspendInlineFunctionGenerationStrategy(
state,
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
function,
v.getThisName(),
state.getConstructorCallNormalizationMode(),
this
);
}
} else {
strategy = new FunctionGenerationStrategy.FunctionDefault(state, function);
}
@@ -202,12 +216,12 @@ public class FunctionCodegen {
MethodVisitor mv =
strategy.wrapMethodVisitor(
v.newMethod(origin,
flags,
asmMethod.getName(),
asmMethod.getDescriptor(),
jvmSignature.getGenericsSignature(),
getThrownExceptions(functionDescriptor, typeMapper)
newMethod(origin,
flags,
asmMethod.getName(),
asmMethod.getDescriptor(),
jvmSignature.getGenericsSignature(),
getThrownExceptions(functionDescriptor, typeMapper)
),
flags, asmMethod.getName(),
asmMethod.getDescriptor()
@@ -254,6 +268,18 @@ public class FunctionCodegen {
}
}
@NotNull
public MethodVisitor newMethod(
@NotNull JvmDeclarationOrigin origin,
int access,
@NotNull String name,
@NotNull String desc,
@Nullable String signature,
@Nullable String[] exceptions
) {
return v.newMethod(origin, access, name, desc, signature, exceptions);
}
private static boolean shouldDelegateMethodBodyToInlineClass(
@NotNull JvmDeclarationOrigin origin,
@NotNull FunctionDescriptor functionDescriptor,
@@ -28,10 +28,10 @@ import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class SuspendFunctionGenerationStrategy(
open class SuspendFunctionGenerationStrategy(
state: GenerationState,
private val originalSuspendDescriptor: FunctionDescriptor,
private val declaration: KtFunction,
protected val originalSuspendDescriptor: FunctionDescriptor,
protected val declaration: KtFunction,
private val containingClassInternalName: String,
private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode
) : FunctionGenerationStrategy.CodegenBased(state) {
@@ -0,0 +1,105 @@
/*
* Copyright 2010-2018 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.coroutines
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.FunctionCodegen
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.MethodNode
// For named suspend function we generate two methods:
// 1) to use as noinline function, which have state machine
// 2) to use from inliner: private one without state machine
class SuspendInlineFunctionGenerationStrategy(
state: GenerationState,
originalSuspendDescriptor: FunctionDescriptor,
declaration: KtFunction,
containingClassInternalName: String,
constructorCallNormalizationMode: JVMConstructorCallNormalizationMode,
private val codegen: FunctionCodegen
) : SuspendFunctionGenerationStrategy(
state,
originalSuspendDescriptor,
declaration,
containingClassInternalName,
constructorCallNormalizationMode
) {
private val defaultStrategy = FunctionGenerationStrategy.FunctionDefault(state, declaration)
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
if (access and Opcodes.ACC_ABSTRACT != 0) return mv
return MethodNodeCopyingMethodVisitor(
super.wrapMethodVisitor(mv, access, name, desc),
access,
name,
desc = desc,
signature = null,
exceptions = null,
codegen = codegen,
declaration = declaration,
originalSuspendDescriptor = originalSuspendDescriptor,
isReleaseCoroutines = state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
)
}
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
super.doGenerateBody(codegen, signature)
defaultStrategy.doGenerateBody(codegen, signature)
}
private class MethodNodeCopyingMethodVisitor(
delegate: MethodVisitor,
private val access: Int,
private val name: String,
private val desc: String,
private val signature: String?,
private val exceptions: Array<out String>?,
private val codegen: FunctionCodegen,
private val declaration: KtFunction,
private val originalSuspendDescriptor: FunctionDescriptor,
private val isReleaseCoroutines: Boolean
) : TransformationMethodVisitor(
delegate,
calculateAccessForInline(access),
"$name\$\$forInline",
desc,
signature,
exceptions
) {
override fun performTransformations(methodNode: MethodNode) {
val newMethodNode = codegen.newMethod(
OtherOrigin(declaration, getOrCreateJvmSuspendFunctionView(originalSuspendDescriptor, isReleaseCoroutines)),
calculateAccessForInline(access), "$name\$\$forInline", desc, signature, exceptions
)
methodNode.instructions.resetLabels()
methodNode.accept(newMethodNode)
}
}
companion object {
private fun calculateAccessForInline(access: Int): Int {
var accessForInline = access
if (accessForInline and Opcodes.ACC_PUBLIC != 0) {
accessForInline = accessForInline xor Opcodes.ACC_PUBLIC
}
if (accessForInline and Opcodes.ACC_PROTECTED != 0) {
accessForInline = accessForInline xor Opcodes.ACC_PROTECTED
}
return accessForInline or Opcodes.ACC_PRIVATE
}
}
}
@@ -503,7 +503,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
val asmMethod = if (callDefault)
state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompilerForInline.contextKind)
else
jvmSignature.asmMethod
mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
val methodId = MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.containingDeclaration), asmMethod)
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
@@ -511,16 +511,26 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return sourceCompilerForInline.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod)
}
val resultInCache = state.inlineCache.methodNodeById.getOrPut(
methodId
) {
doCreateMethodNodeFromCompiled(directMember, state, asmMethod)
?: throw IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor)
val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId) {
val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod)
?: if (functionDescriptor.isSuspend)
doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod)
else
null
result ?: throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor")
}
return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.node))
}
// For suspend inline functions we generate two methods:
// 1) normal one: with state machine to call directly
// 2) for inliner: with mangled name and without state machine
private fun mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor: FunctionDescriptor, asmMethod: Method): Method {
if (!functionDescriptor.isSuspend) return asmMethod
return Method("${asmMethod.name}\$\$forInline", asmMethod.descriptor)
}
private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor {
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: NATIVE
// IGNORE_BACKEND: JVM
// WITH_COROUTINES
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
@@ -23,13 +23,29 @@ final class InlineWithStateMachineKt$mainSuspend$1 {
synthetic final method setLabel(p0: int): void
}
@kotlin.Metadata
public final class InlineWithStateMachineKt$suspendHere$1 {
field L$0: java.lang.Object
field L$1: java.lang.Object
synthetic field data: java.lang.Object
synthetic field exception: java.lang.Throwable
inner class InlineWithStateMachineKt$suspendHere$1
public method <init>(p0: COROUTINES_PACKAGE.Continuation): void
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
synthetic final method getLabel(): int
synthetic final method setLabel(p0: int): void
}
@kotlin.Metadata
public final class InlineWithStateMachineKt {
inner class InlineWithStateMachineKt$box$1
inner class InlineWithStateMachineKt$mainSuspend$1
inner class InlineWithStateMachineKt$suspendHere$1
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
public final static @org.jetbrains.annotations.Nullable method mainSuspend(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object
private final static method suspendHere(p0: COROUTINES_PACKAGE.Continuation): java.lang.Object
private final static method suspendThere(p0: java.lang.String, p1: COROUTINES_PACKAGE.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method suspendHere$$forInline(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method suspendThere$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object
}
@@ -31,5 +31,6 @@ public final class InlineWithoutStateMachineKt {
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
public final static @org.jetbrains.annotations.Nullable method complexSuspend(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object
private final static method suspendThere(p0: java.lang.String, p1: COROUTINES_PACKAGE.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method suspendThere$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object
}
@@ -0,0 +1,71 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
var result = "FAIL"
var i = 0
var finished = false
var proceed: () -> Unit = {}
suspend fun suspendHere() = suspendCoroutine<Unit> {
i++
proceed = { it.resume(Unit) }
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.InlineOnly
inline suspend fun inlineMe() {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
val continuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
proceed = {
result = "OK"
finished = true
}
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
c.startCoroutine(continuation)
}
suspend fun inlineSite() {
inlineMe()
inlineMe()
}
fun box(): String {
builder {
inlineSite()
}
for (counter in 0 until 10) {
if (i != counter + 1) return "Expected ${counter + 1}, got $i"
proceed()
}
if (i != 10) return "FAIL $i"
if (finished) return "resume on root continuation is called"
proceed()
if (!finished) return "resume on root continuation is not called"
return result
}
@@ -0,0 +1,69 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
var result = "FAIL"
var i = 0
var finished = false
var proceed: () -> Unit = {}
suspend fun suspendHere() = suspendCoroutine<Unit> {
i++
proceed = { it.resume(Unit) }
}
inline suspend fun inlineMe() {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
val continuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
proceed = {
result = "OK"
finished = true
}
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
c.startCoroutine(continuation)
}
suspend fun inlineSite() {
inlineMe()
inlineMe()
}
fun box(): String {
builder {
inlineSite()
}
for (counter in 0 until 10) {
if (i != counter + 1) return "Expected ${counter + 1}, got $i"
proceed()
}
if (i != 10) return "FAIL $i"
if (finished) return "resume on root continuation is called"
proceed()
if (!finished) return "resume on root continuation is not called"
return result
}
@@ -0,0 +1,39 @@
// WITH_RUNTIME
suspend inline fun simple() {}
suspend inline fun <T> generic() {}
suspend inline fun <T, reified U> genericWithReified() {}
suspend inline fun Unit.simple() {}
suspend inline fun <T> T.generic() {}
suspend inline fun <T, reified U> T.genericWithReified() {}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.InlineOnly
suspend inline fun shouldNotHaveSuffix() {}
suspend inline fun acceptsCrossinline(crossinline c: () -> Unit) {}
class Foo {
suspend inline fun simple() {}
suspend inline fun <T> generic() {}
suspend inline fun <T, reified U> genericWithReified() {}
suspend inline fun Unit.simple() {}
suspend inline fun <T> T.generic() {}
suspend inline fun <T, reified U> T.genericWithReified() {}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.InlineOnly
suspend inline fun shouldNotHaveSuffix() {}
suspend inline fun acceptsCrossinline(crossinline c: () -> Unit) {}
}
@@ -0,0 +1,32 @@
@kotlin.Metadata
public final class Foo {
public method <init>(): void
private final method acceptsCrossinline(p0: kotlin.jvm.functions.Function0, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final @org.jetbrains.annotations.Nullable method generic$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final @org.jetbrains.annotations.Nullable method generic(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final method genericWithReified(p0: java.lang.Object, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final method genericWithReified(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final @kotlin.internal.InlineOnly method shouldNotHaveSuffix(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
}
@kotlin.Metadata
public final class SimpleNamedKt {
private final static method acceptsCrossinline(p0: kotlin.jvm.functions.Function0, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method generic$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method generic(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static method genericWithReified(p0: java.lang.Object, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static method genericWithReified(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static @kotlin.internal.InlineOnly method shouldNotHaveSuffix(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
}
@@ -107,6 +107,7 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
override fun shouldWriteMethod(access: Int, name: String, desc: String) = when {
name == "<clinit>" -> false
name.contains("\$\$forInline") -> false
AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.descriptor in desc -> false
name.startsWith("access$") && (access and ACC_STATIC != 0) && (access and ACC_SYNTHETIC != 0) -> false
else -> true
@@ -128,6 +128,9 @@ object InlineTestUtil {
if (skipMethodsOfThisClass) {
return null
}
if (name == "doResume" && desc == "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;") {
return null
}
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) {
@@ -7059,25 +7059,13 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
@TestMetadata("inlineMultiModuleOverride.kt")
public void testInlineMultiModuleOverride_1_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
try {
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental");
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental");
}
@TestMetadata("inlineMultiModuleOverride.kt")
public void testInlineMultiModuleOverride_1_3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
try {
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
@TestMetadata("inlineMultiModuleWithController.kt")
@@ -3422,6 +3422,29 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineUsedAsNoinline extends AbstractIrBlackBoxInlineCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOnly.kt")
public void testInlineOnly() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt");
}
@TestMetadata("simpleNamed.kt")
public void testSimpleNamed() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3422,6 +3422,29 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineUsedAsNoinline extends AbstractIrCompileKotlinAgainstInlineKotlinTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOnly.kt")
public void testInlineOnly() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt");
}
@TestMetadata("simpleNamed.kt")
public void testSimpleNamed() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -7059,25 +7059,13 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
@TestMetadata("inlineMultiModuleOverride.kt")
public void testInlineMultiModuleOverride_1_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
try {
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental");
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental");
}
@TestMetadata("inlineMultiModuleOverride.kt")
public void testInlineMultiModuleOverride_1_3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
try {
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
@TestMetadata("inlineMultiModuleWithController.kt")
@@ -3422,6 +3422,29 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineUsedAsNoinline extends AbstractBlackBoxInlineCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOnly.kt")
public void testInlineOnly() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt");
}
@TestMetadata("simpleNamed.kt")
public void testSimpleNamed() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -253,6 +253,24 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/inline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Inline extends AbstractBytecodeListingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInInline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/inline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("simpleNamed.kt")
public void testSimpleNamed() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/inline/simpleNamed.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/inlineClasses")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3422,6 +3422,29 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineUsedAsNoinline extends AbstractCompileKotlinAgainstInlineKotlinTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOnly.kt")
public void testInlineOnly() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt");
}
@TestMetadata("simpleNamed.kt")
public void testSimpleNamed() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -7036,30 +7036,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class MultiModule extends AbstractLightAnalysisModeTest {
@TestMetadata("inlineMultiModuleOverride.kt")
public void ignoreInlineMultiModuleOverride_1_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
try {
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental");
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("inlineMultiModuleOverride.kt")
public void ignoreInlineMultiModuleOverride_1_3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
try {
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -7080,6 +7056,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
@TestMetadata("inlineMultiModuleOverride.kt")
public void testInlineMultiModuleOverride_1_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental");
}
@TestMetadata("inlineMultiModuleOverride.kt")
public void testInlineMultiModuleOverride_1_3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines");
}
@TestMetadata("inlineMultiModuleWithController.kt")
public void testInlineMultiModuleWithController_1_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleWithController.kt");
@@ -73,7 +73,7 @@ fun MemberDescriptor.isInlineOnlyOrReifiable(): Boolean =
this is CallableMemberDescriptor && (isReifiable() || DescriptorUtils.getDirectMember(this).isReifiable() || isInlineOnly())
fun MemberDescriptor.isEffectivelyInlineOnly(): Boolean =
isInlineOnlyOrReifiable() || safeAs<FunctionDescriptor>()?.let { it.isSuspend && it.isInline } == true
isInlineOnlyOrReifiable() || (this is FunctionDescriptor && this.isSuspend && this.valueParameters.any { it.isCrossinline })
fun MemberDescriptor.isInlineOnly(): Boolean {
if (this !is FunctionDescriptor ||