diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 314a875e23d..3e64f36f1bd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -125,7 +125,8 @@ public class FunctionCodegen { CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), function, v.getThisName(), - state.getConstructorCallNormalizationMode() + state.getConstructorCallNormalizationMode(), + this ); } else { strategy = new SuspendInlineFunctionGenerationStrategy( @@ -1642,4 +1643,9 @@ public class FunctionCodegen { } } } + + @Nullable + public Map getCaptureVariables() { + return owner.closure == null ? null : owner.closure.getCaptureVariables(); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index a4ccd405c02..039aa8579e8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -6,11 +6,14 @@ package org.jetbrains.kotlin.codegen.coroutines import com.intellij.util.ArrayUtil +import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA import org.jetbrains.kotlin.codegen.context.ClosureContext +import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor import org.jetbrains.kotlin.codegen.context.MethodContext +import org.jetbrains.kotlin.codegen.inline.coroutines.SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.config.LanguageFeature @@ -462,10 +465,8 @@ class CoroutineCodegenForLambda private constructor( object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) { override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { - val addEndLabelMethodVisitor = AddEndLabelMethodVisitor(mv, access, name, desc, endLabel) - if (forInline) return super.wrapMethodVisitor(addEndLabelMethodVisitor, access, name, desc) - return CoroutineTransformerMethodVisitor( - addEndLabelMethodVisitor, access, name, desc, null, null, + val stateMachineBuilder = CoroutineTransformerMethodVisitor( + mv, access, name, desc, null, null, obtainClassBuilderForCoroutineState = { v }, element = element, diagnostics = state.diagnostics, @@ -474,6 +475,17 @@ class CoroutineCodegenForLambda private constructor( isForNamedFunction = false, languageVersionSettings = languageVersionSettings ) + return if (forInline) AddEndLabelMethodVisitor( + MethodNodeCopyingMethodVisitor( + SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( + stateMachineBuilder, access, name, desc, v.thisName, + isCapturedSuspendLambda = { isCapturedSuspendLambda(closure.captureVariables, it.name) } + ), access, name, desc, + newMethod = { origin, newAccess, newName, newDesc -> + functionCodegen.newMethod(origin, newAccess, newName, newDesc, null, null) + } + ), access, name, desc, endLabel + ) else AddEndLabelMethodVisitor(stateMachineBuilder, access, name, desc, endLabel) } override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { @@ -516,13 +528,22 @@ class CoroutineCodegenForLambda private constructor( } } +fun isCapturedSuspendLambda(captureVariables: Map, name: String): Boolean { + for ((param, value) in captureVariables) { + if (param !is ValueParameterDescriptor) continue + if (value.fieldName != name) continue + return param.type.isSuspendFunctionTypeOrSubtype + } + return false +} + private class AddEndLabelMethodVisitor( delegate: MethodVisitor, access: Int, name: String, desc: String, private val endLabel: Label -): TransformationMethodVisitor(delegate, access, name, desc, null, null) { +) : TransformationMethodVisitor(delegate, access, name, desc, null, null) { override fun performTransformations(methodNode: MethodNode) { methodNode.instructions.add( withInstructionAdapter { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 7f77c2a85db..a8bfeb5b4de 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -48,6 +48,7 @@ private const val COROUTINES_METADATA_VERSION_JVM_NAME = "v" const val SUSPEND_FUNCTION_CONTINUATION_PARAMETER = "\$completion" const val SUSPEND_CALL_RESULT_NAME = "\$result" +const val ILLEGAL_STATE_ERROR_MESSAGE = "call to 'resume' before 'invoke' with coroutine" class CoroutineTransformerMethodVisitor( delegate: MethodVisitor, @@ -176,7 +177,7 @@ class CoroutineTransformerMethodVisitor( insert(last, defaultLabel) insert(last, withInstructionAdapter { - AsmUtil.genThrow(this, "java/lang/IllegalStateException", "call to 'resume' before 'invoke' with coroutine") + AsmUtil.genThrow(this, "java/lang/IllegalStateException", ILLEGAL_STATE_ERROR_MESSAGE) areturn(Type.VOID_TYPE) }) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt index 5e94791058f..795a0e96698 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -5,12 +5,10 @@ package org.jetbrains.kotlin.codegen.coroutines -import org.jetbrains.kotlin.codegen.ClassBuilder -import org.jetbrains.kotlin.codegen.ExpressionCodegen -import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy -import org.jetbrains.kotlin.codegen.TransformationMethodVisitor +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.inline.addFakeContinuationConstructorCallMarker +import org.jetbrains.kotlin.codegen.inline.coroutines.SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -22,17 +20,19 @@ import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.kotlin.utils.sure 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.tree.MethodNode open class SuspendFunctionGenerationStrategy( - state: GenerationState, - protected val originalSuspendDescriptor: FunctionDescriptor, - protected val declaration: KtFunction, - private val containingClassInternalName: String, - private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode + state: GenerationState, + protected val originalSuspendDescriptor: FunctionDescriptor, + protected val declaration: KtFunction, + private val containingClassInternalName: String, + private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, + protected val functionCodegen: FunctionCodegen ) : FunctionGenerationStrategy.CodegenBased(state) { private lateinit var codegen: ExpressionCodegen @@ -45,7 +45,7 @@ open class SuspendFunctionGenerationStrategy( declaration.containingFile ).also { val coroutineCodegen = - CoroutineCodegenForNamedFunction.create(it, codegen, originalSuspendDescriptor, declaration) + CoroutineCodegenForNamedFunction.create(it, codegen, originalSuspendDescriptor, declaration) coroutineCodegen.generate() } } @@ -53,16 +53,7 @@ open class SuspendFunctionGenerationStrategy( override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { if (access and Opcodes.ACC_ABSTRACT != 0) return mv - if (state.bindingContext[CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA, originalSuspendDescriptor] == true) { - return AddConstructorCallForCoroutineRegeneration( - mv, access, name, desc, null, null, this::classBuilderForCoroutineState, - containingClassInternalName, - originalSuspendDescriptor.dispatchReceiverParameter != null, - containingClassInternalNameOrNull(), - languageVersionSettings - ) - } - return CoroutineTransformerMethodVisitor( + val stateMachineBuilder = CoroutineTransformerMethodVisitor( mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState, isForNamedFunction = true, element = declaration, @@ -72,10 +63,37 @@ open class SuspendFunctionGenerationStrategy( internalNameForDispatchReceiver = containingClassInternalNameOrNull(), languageVersionSettings = languageVersionSettings ) + + val forInline = state.bindingContext[CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA, originalSuspendDescriptor] == true + // Yegor Bugayenko style + return if (forInline) + AddConstructorCallForCoroutineRegeneration( + MethodNodeCopyingMethodVisitor( + SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( + stateMachineBuilder, + access, name, desc, containingClassInternalName, + isCapturedSuspendLambda = { + isCapturedSuspendLambda( + functionCodegen.captureVariables.sure { + "Anonymous object should have closure" + }, + it.name + ) + } + ), access, name, desc, + newMethod = { origin, newAccess, newName, newDesc -> + functionCodegen.newMethod(origin, newAccess, newName, newDesc, null, null) + } + ), access, name, desc, null, null, this::classBuilderForCoroutineState, + containingClassInternalName, + originalSuspendDescriptor.dispatchReceiverParameter != null, + containingClassInternalNameOrNull(), + languageVersionSettings + ) else stateMachineBuilder } private fun containingClassInternalNameOrNull() = - originalSuspendDescriptor.containingDeclaration.safeAs()?.let(state.typeMapper::mapClass)?.internalName + originalSuspendDescriptor.containingDeclaration.safeAs()?.let(state.typeMapper::mapClass)?.internalName override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { this.codegen = codegen @@ -115,6 +133,7 @@ open class SuspendFunctionGenerationStrategy( languageVersionSettings ) addFakeContinuationConstructorCallMarker(this, false) + pop() // Otherwise stack-transformation breaks }) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt index 65438994899..f580330499b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.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. */ @@ -9,12 +9,12 @@ 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.inline.coroutines.FOR_INLINE_SUFFIX 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.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes @@ -29,13 +29,14 @@ class SuspendInlineFunctionGenerationStrategy( declaration: KtFunction, containingClassInternalName: String, constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, - private val codegen: FunctionCodegen + codegen: FunctionCodegen ) : SuspendFunctionGenerationStrategy( state, originalSuspendDescriptor, declaration, containingClassInternalName, - constructorCallNormalizationMode + constructorCallNormalizationMode, + codegen ) { private val defaultStrategy = FunctionGenerationStrategy.FunctionDefault(state, declaration) @@ -43,16 +44,10 @@ class SuspendInlineFunctionGenerationStrategy( 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) + super.wrapMethodVisitor(mv, access, name, desc), access, name, desc, + newMethod = { origin, newAccess, newName, newDesc -> + functionCodegen.newMethod(origin, newAccess, newName, newDesc, null, null) + }, keepAccess = false ) } @@ -60,46 +55,26 @@ class SuspendInlineFunctionGenerationStrategy( 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?, - 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) - } +class MethodNodeCopyingMethodVisitor( + delegate: MethodVisitor, private val access: Int, private val name: String, private val desc: String, + private val newMethod: (JvmDeclarationOrigin, Int, String, String) -> MethodVisitor, + private val keepAccess: Boolean = true +) : TransformationMethodVisitor( + delegate, calculateAccessForInline(access, keepAccess), "$name$FOR_INLINE_SUFFIX", desc, null, null +) { + override fun performTransformations(methodNode: MethodNode) { + val newMethodNode = newMethod( + JvmDeclarationOrigin.NO_ORIGIN, calculateAccessForInline(access, keepAccess), "$name$FOR_INLINE_SUFFIX", desc + ) + 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 - } + private fun calculateAccessForInline(access: Int, keepAccess: Boolean): Int = + if (keepAccess) access + else access or Opcodes.ACC_PRIVATE and Opcodes.ACC_PUBLIC.inv() and Opcodes.ACC_PROTECTED.inv() } -} \ No newline at end of file +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index 356a0a5ecc3..ced9eb9be7b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -7,6 +7,8 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.util.ArrayUtil import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.coroutines.DEBUG_METADATA_ANNOTATION_ASM_TYPE +import org.jetbrains.kotlin.codegen.coroutines.isCapturedSuspendLambda import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable @@ -67,6 +69,8 @@ class AnonymousObjectTransformer( // Empty inner class info because no inner classes are used in kotlin.Metadata and its arguments val innerClassesInfo = FileBasedKotlinClass.InnerClassesInfo() return FileBasedKotlinClass.convertAnnotationVisitor(metadataReader, desc, innerClassesInfo) + } else if (desc == DEBUG_METADATA_ANNOTATION_ASM_TYPE.descriptor) { + return null } return super.visitAnnotation(desc, visible) } @@ -135,12 +139,13 @@ class AnonymousObjectTransformer( classBuilder, methodsToTransform, superClassName, - additionalFakeParams + allCapturedParamBuilder.listCaptured() ) - for (next in methodsToTransform) { + loop@for (next in methodsToTransform) { val deferringVisitor = when { - coroutineTransformer.shouldTransform(next) -> coroutineTransformer.newMethod(next) + coroutineTransformer.shouldSkip(next) -> continue@loop + coroutineTransformer.shouldGenerateStateMachine(next) -> coroutineTransformer.newMethod(next) else -> newMethod(classBuilder, next) } val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false) @@ -479,6 +484,11 @@ class AnonymousObjectTransformer( alreadyAddedParam?.newFieldName ?: getNewFieldName(desc.fieldName, false), alreadyAddedParam != null ) + if (info is PsiExpressionLambda && info.captureVariables.any { it.value.fieldName == desc.fieldName }) { + recapturedParamInfo.functionalArgument = NonInlineableArgumentForInlineableParameterCalledInSuspend( + isCapturedSuspendLambda(info.captureVariables, desc.fieldName) + ) + } val composed = StackValue.field( desc.type, oldObjectType, /*TODO owner type*/ 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 300f23d0908..b831a40c417 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.ClosureContext +import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -575,7 +576,7 @@ abstract class InlineCodegen( // 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) + return Method("${asmMethod.name}$FOR_INLINE_SUFFIX", asmMethod.descriptor) } private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 91cd3b1be69..44d451b2002 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -307,4 +307,6 @@ class PsiExpressionLambda( val isPropertyReference: Boolean get() = propertyReferenceInfo != null + + val captureVariables = closure.captureVariables } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java index 25c682c5942..4576a6206c4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the 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; @@ -29,9 +18,13 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.commons.*; import org.jetbrains.org.objectweb.asm.commons.FieldRemapper; +import java.util.HashMap; +import java.util.Map; + public class RemappingClassBuilder extends DelegatingClassBuilder { private final ClassBuilder builder; private final Remapper remapper; + private final Map spilledCoroutineVariables = new HashMap<>(); public RemappingClassBuilder(@NotNull ClassBuilder builder, @NotNull Remapper remapper) { this.builder = builder; @@ -68,9 +61,39 @@ public class RemappingClassBuilder extends DelegatingClassBuilder { @Nullable String signature, @Nullable Object value ) { - return new FieldRemapper( - builder.newField(origin, access, name, remapper.mapDesc(desc), remapper.mapSignature(signature, true), value), remapper + if (spilledCoroutineVariables.containsKey(name)) return spilledCoroutineVariables.get(name); + + FieldRemapper field = new FieldRemapper( + builder.newField(origin, access, name, this.remapper.mapDesc(desc), this.remapper.mapSignature(signature, true), value), + this.remapper ); + if (isSpilledCoroutineVariableName(name)) { + spilledCoroutineVariables.put(name, field); + } + return field; + } + + private static boolean isSpilledCoroutineVariableName(String name) { + if (name.length() < 3) return false; + switch (name.charAt(0)) { + case 'L': + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + break; + default: + return false; + } + if (name.charAt(1) != '$') return false; + for (int i = 2; i < name.length(); ++i) { + if (!Character.isDigit(name.charAt(i))) return false; + } + return true; } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt index ab5d5932a2c..a7ef66be78e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.codegen.inline.coroutines import com.intellij.util.ArrayUtil +import org.jetbrains.kotlin.codegen.AsmUtil.CAPTURED_THIS_FIELD import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.TransformationMethodVisitor import org.jetbrains.kotlin.codegen.coroutines.* @@ -16,7 +17,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.config.isReleaseCoroutines -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.utils.addToStdlib.cast @@ -29,6 +29,8 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue const val NOINLINE_CALL_MARKER = "NOINLINE_CALL_MARKER" +const val FOR_INLINE_SUFFIX = "\$\$forInline" + class CoroutineTransformer( private val inliningContext: InliningContext, private val classBuilder: ClassBuilder, @@ -37,24 +39,20 @@ class CoroutineTransformer( private val capturedParams: List ) { private val state = inliningContext.state + // If we inline into inline function, we should generate both method with state-machine for Java interop and method without + // state-machine for further transformation/inlining. + private val generateForInline = inliningContext.callSiteInfo.isInlineOrInsideInline - fun shouldTransform(node: MethodNode): Boolean { - // Never generate state-machine for objects, which are going to be retransformed - // See innerObjectRetransformation.kt - if (inliningContext.callSiteInfo.isInlineOrInsideInline) return false + fun shouldSkip(node: MethodNode): Boolean = methods.any { it.name == node.name + FOR_INLINE_SUFFIX && it.desc == node.desc } + + fun shouldGenerateStateMachine(node: MethodNode): Boolean { + // Continuations are similar to lambdas from bird's view, but we should never generate state machine for them if (isContinuationNotLambda()) return false - val crossinlineParam = crossinlineLambda() - if (inliningContext.isInliningLambda && !inliningContext.isContinuation) return false - return when { - isSuspendFunction(node) -> true - isSuspendLambda(node) -> { - if (isStateMachine(node)) return false - val functionDescriptor = - crossinlineParam?.invokeMethodDescriptor?.containingDeclaration as? FunctionDescriptor ?: return true - !functionDescriptor.isInline - } - else -> false - } + // The method does not have state-machine, but should. Generate it + if (node.name.endsWith(FOR_INLINE_SUFFIX)) return true + // there can be suspend lambdas inside inline functions, which do not + // capture crossinline lambdas, thus, there is no need to transform them + return isSuspendFunctionWithFakeConstructorCall(node) || (isSuspendLambda(node) && !isStateMachine(node)) } private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation && @@ -66,7 +64,7 @@ class CoroutineTransformer( }?.cast() private fun isStateMachine(node: MethodNode): Boolean = - node.instructions.asSequence().any { it.opcode == Opcodes.INVOKESTATIC && (it as MethodInsnNode).name == "getCOROUTINE_SUSPENDED" } + node.instructions.asSequence().any { insn -> insn is LdcInsnNode && insn.cst == ILLEGAL_STATE_ERROR_MESSAGE } private fun isSuspendLambda(node: MethodNode) = isResumeImpl(node) @@ -83,28 +81,29 @@ class CoroutineTransformer( } newStateMachineForLambda(node, element) } - isSuspendFunction(node) -> newStateMachineForNamedFunction(node, element) + isSuspendFunctionWithFakeConstructorCall(node) -> newStateMachineForNamedFunction(node, element) else -> error("no need to generate state maching for ${node.name}") } } private fun isResumeImpl(node: MethodNode): Boolean = - state.languageVersionSettings.isResumeImplMethodName(node.name) && + state.languageVersionSettings.isResumeImplMethodName(node.name.removeSuffix(FOR_INLINE_SUFFIX)) && inliningContext.isContinuation - private fun isSuspendFunction(node: MethodNode): Boolean = findFakeContinuationConstructorClassName(node) != null + private fun isSuspendFunctionWithFakeConstructorCall(node: MethodNode): Boolean = findFakeContinuationConstructorClassName(node) != null private fun newStateMachineForLambda(node: MethodNode, element: KtElement): DeferredMethodVisitor { + val name = node.name.removeSuffix(FOR_INLINE_SUFFIX) return DeferredMethodVisitor( MethodNode( - node.access, node.name, node.desc, node.signature, + node.access, name, node.desc, node.signature, ArrayUtil.toStringArray(node.exceptions) ) ) { - surroundNoinlineCallsWithMarkersIfNeeded( + val stateMachineBuilder = surroundNoinlineCallsWithMarkersIfNeeded( node, CoroutineTransformerMethodVisitor( - createNewMethodFrom(node), node.access, node.name, node.desc, null, null, + createNewMethodFrom(node, name), node.access, name, node.desc, null, null, obtainClassBuilderForCoroutineState = { classBuilder }, element = element, diagnostics = state.diagnostics, @@ -114,22 +113,36 @@ class CoroutineTransformer( isForNamedFunction = false ) ) + + if (generateForInline) + MethodNodeCopyingMethodVisitor( + delegate = stateMachineBuilder, + access = node.access, + name = name, + desc = node.desc, + newMethod = { origin, newAccess, newName, newDesc -> + classBuilder.newMethod(origin, newAccess, newName, newDesc, null, null) + } + ) + else + stateMachineBuilder } } private fun newStateMachineForNamedFunction(node: MethodNode, element: KtElement): DeferredMethodVisitor { + val name = node.name.removeSuffix(FOR_INLINE_SUFFIX) val continuationClassName = findFakeContinuationConstructorClassName(node) assert(inliningContext is RegeneratedClassContext) return DeferredMethodVisitor( MethodNode( - node.access, node.name, node.desc, node.signature, + node.access, name, node.desc, node.signature, ArrayUtil.toStringArray(node.exceptions) ) ) { - surroundNoinlineCallsWithMarkersIfNeeded( + val stateMachineBuilder = surroundNoinlineCallsWithMarkersIfNeeded( node, CoroutineTransformerMethodVisitor( - createNewMethodFrom(node), node.access, node.name, node.desc, null, null, + createNewMethodFrom(node, name), node.access, name, node.desc, null, null, obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! }, element = element, diagnostics = state.diagnostics, @@ -141,30 +154,33 @@ class CoroutineTransformer( internalNameForDispatchReceiver = classBuilder.thisName ) ) + + if (generateForInline) + MethodNodeCopyingMethodVisitor( + stateMachineBuilder, node.access, name, node.desc, + newMethod = { origin, newAccess, newName, newDesc -> + classBuilder.newMethod(origin, newAccess, newName, newDesc, null, null) + } + ) + else + stateMachineBuilder } } private fun surroundNoinlineCallsWithMarkersIfNeeded(node: MethodNode, delegate: MethodVisitor): MethodVisitor = - if (capturedParams.any { (it.functionalArgument as? NonInlineableArgumentForInlineableParameterCalledInSuspend)?.isSuspend == true }) + if (capturedParams.any { it.functionalArgument?.isSuspendLambda() == true }) SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( - delegate, - node.access, - node.name, - node.desc, - classBuilder.thisName, - capturedParams + delegate, node.access, node.name, node.desc, classBuilder.thisName, this::isCapturedSuspendLambda ) else delegate - private fun createNewMethodFrom(node: MethodNode): MethodVisitor { + private fun isCapturedSuspendLambda(field: FieldInsnNode): Boolean = + capturedParams.find { it.newFieldName == field.name }?.functionalArgument?.isSuspendLambda() == true + + private fun createNewMethodFrom(node: MethodNode, name: String): MethodVisitor { return classBuilder.newMethod( - JvmDeclarationOrigin.NO_ORIGIN, - node.access, - node.name, - node.desc, - node.signature, - ArrayUtil.toStringArray(node.exceptions) + JvmDeclarationOrigin.NO_ORIGIN, node.access, name, node.desc, node.signature, ArrayUtil.toStringArray(node.exceptions) ) } @@ -193,13 +209,10 @@ class CoroutineTransformer( } } -private class SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( - delegate: MethodVisitor, - access: Int, - name: String, - desc: String, - val thisName: String, - val capturedParams: List +class SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( + delegate: MethodVisitor, access: Int, name: String, desc: String, + private val thisName: String, + private val isCapturedSuspendLambda: (FieldInsnNode) -> Boolean ) : TransformationMethodVisitor(delegate, access, name, desc, null, null) { override fun performTransformations(methodNode: MethodNode) { fun AbstractInsnNode.index() = methodNode.instructions.indexOf(this) @@ -213,7 +226,7 @@ private class SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( insn as MethodInsnNode if (!isInvokeOnLambda(insn.owner, insn.name)) continue val frame = sourceFrames[insn.index()] - val receiver = findReceiverOfInvoke(frame, insn).takeIf { it?.isNoinlineSuspendLambda(insn) == true } as? FieldInsnNode ?: continue + val receiver = findReceiverOfInvoke(frame, insn).takeIf { it?.isSuspendLambda(insn) == true } as? FieldInsnNode ?: continue val aload = receiver.findPreviousOrNull { it.opcode != Opcodes.GETFIELD } ?: error("GETFIELD cannot be the first instruction") assert(aload.opcode == Opcodes.ALOAD) { "Before GETFIELD there shall be ALOAD" } noinlineInvokes.add(insn to aload) @@ -222,15 +235,29 @@ private class SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( surroundInvokesWithSuspendMarkers(methodNode, noinlineInvokes) } - private fun AbstractInsnNode.isNoinlineSuspendLambda(invoke: MethodInsnNode): Boolean { + private fun AbstractInsnNode.isSuspendLambda(invoke: MethodInsnNode): Boolean { if (opcode != Opcodes.GETFIELD) return false this as FieldInsnNode - if (owner != thisName || desc != "L${invoke.owner};") return false - val functionalArgument = capturedParams.find { it.newFieldName == name }?.functionalArgument ?: return false - return functionalArgument is NonInlineableArgumentForInlineableParameterCalledInSuspend && functionalArgument.isSuspend + if (desc != "L${invoke.owner};") return false + var current: FieldInsnNode? = this + // Unroll the battery of + // GETFIELD .this$0 L; + // GETFIELD .this$0 L; + // ... + // GETFIELD .$action Lkotlin/jvm/functions/FunctionM; + while (current != null) { + if (current.owner == thisName) break + if (current.previous?.opcode != Opcodes.GETFIELD || current.previous.cast().name != CAPTURED_THIS_FIELD) return false + current = current.previous as FieldInsnNode + } + return isCapturedSuspendLambda(this) } } +private fun FunctionalArgument.isSuspendLambda(): Boolean = + (this is NonInlineableArgumentForInlineableParameterCalledInSuspend && isSuspend) || + (this is PsiExpressionLambda && invokeMethodDescriptor.isSuspend) + fun surroundInvokesWithSuspendMarkers( methodNode: MethodNode, noinlineInvokes: List> diff --git a/compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt b/compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt new file mode 100644 index 00000000000..4a4c7b0a38f --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt @@ -0,0 +1,103 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// NO_CHECK_LAMBDA_INLINING +// CHECK_STATE_MACHINE + +// FILE: inlineMe.kt + +package test + +inline fun inlineMe(crossinline c: suspend () -> Unit) = suspend { c(); c() } + +inline fun inlineMe2(crossinline c: suspend () -> Unit) = inlineMe { c(); c() } + +inline fun inlineMe3(crossinline c: suspend () -> Unit) = suspend { + var sr = inlineMe { + c() + c() + } + sr() + sr = inlineMe { + c() + c() + } + sr() +} + +// FILE: A.java + +import test.InlineMeKt; +import helpers.CoroutineUtilKt; +import helpers.EmptyContinuation; +import kotlin.Unit; + +public class A { + public static Object call() { + return InlineMeKt.inlineMe((continuation) -> CoroutineUtilKt.getStateMachineChecker().suspendHere(continuation)); + } + public static Object call2() { + return InlineMeKt.inlineMe2((continuation) -> CoroutineUtilKt.getStateMachineChecker().suspendHere(continuation)); + } + public static Object call3() { + return InlineMeKt.inlineMe3((continuation) -> CoroutineUtilKt.getStateMachineChecker().suspendHere(continuation)); + } +} + +// FILE: box.kt + +import test.* +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + builder { + (A.call() as (suspend () -> Unit))() + } + StateMachineChecker.check(2) + StateMachineChecker.reset() + + builder { + (A.call2() as (suspend () -> Unit))() + } + StateMachineChecker.check(4) + StateMachineChecker.reset() + + builder { + (A.call3() as (suspend () -> Unit))() + } + StateMachineChecker.check(8) + StateMachineChecker.reset() + + builder { + inlineMe { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }() + } + StateMachineChecker.check(4) + StateMachineChecker.reset() + + builder { + inlineMe2 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }() + } + StateMachineChecker.check(8) + StateMachineChecker.reset() + + builder { + inlineMe3 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }() + } + StateMachineChecker.check(16) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt b/compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt new file mode 100644 index 00000000000..01fc200d080 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt @@ -0,0 +1,113 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// NO_CHECK_LAMBDA_INLINING +// CHECK_STATE_MACHINE + +// FILE: inlineMe.kt + +package test + +interface SuspendRunnable { + suspend fun run() +} + +inline fun inlineMe(crossinline c: suspend () -> Unit) = object : SuspendRunnable { + override suspend fun run() { + c(); c() + } +} + +inline fun inlineMe2(crossinline c: suspend () -> Unit) = inlineMe { c(); c() } + +inline fun inlineMe3(crossinline c: suspend () -> Unit) = object: SuspendRunnable { + override suspend fun run() { + var sr = inlineMe { + c() + c() + } + sr.run() + sr = inlineMe { + c() + c() + } + sr.run() + } +} + +// FILE: A.java + +import test.InlineMeKt; +import helpers.CoroutineUtilKt; +import helpers.EmptyContinuation; +import kotlin.Unit; + +public class A { + public static Object call() { + return InlineMeKt.inlineMe((continuation) -> CoroutineUtilKt.getStateMachineChecker().suspendHere(continuation)); + } + public static Object call2() { + return InlineMeKt.inlineMe2((continuation) -> CoroutineUtilKt.getStateMachineChecker().suspendHere(continuation)); + } + public static Object call3() { + return InlineMeKt.inlineMe3((continuation) -> CoroutineUtilKt.getStateMachineChecker().suspendHere(continuation)); + } +} + +// FILE: box.kt + +import test.* +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + builder { + (A.call() as SuspendRunnable).run() + } + StateMachineChecker.check(2) + StateMachineChecker.reset() + + builder { + (A.call2() as SuspendRunnable).run() + } + StateMachineChecker.check(4) + StateMachineChecker.reset() + + builder { + (A.call3() as SuspendRunnable).run() + } + StateMachineChecker.check(8) + StateMachineChecker.reset() + + builder { + inlineMe { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }.run() + } + StateMachineChecker.check(4) + StateMachineChecker.reset() + + builder { + inlineMe2 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }.run() + } + StateMachineChecker.check(8) + StateMachineChecker.reset() + + builder { + inlineMe3 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }.run() + } + StateMachineChecker.check(16) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt index 41e099a75b5..4141346df72 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt @@ -1,5 +1,12 @@ @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$box$1$filter$$inlined$source$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object + field L$5: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1 @@ -10,7 +17,12 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$1 { } @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1 @@ -28,6 +40,7 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1 { inner class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 public method (p0: Sink, p1: CrossinlineKt$box$1$filter$$inlined$source$1): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -38,11 +51,18 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1 { inner class CrossinlineKt$box$1$filter$$inlined$source$1 inner class CrossinlineKt$box$1$filter$$inlined$source$1$1 public method (p0: SourceCrossinline, p1: kotlin.jvm.functions.Function1): void + public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$box$1$fold$$inlined$consumeEach$1 @@ -60,6 +80,7 @@ public final class CrossinlineKt$box$1$fold$$inlined$consumeEach$1 { inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1 public method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -119,6 +140,11 @@ public final class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1 { @kotlin.Metadata public final class CrossinlineKt$box$1$invokeSuspend$$inlined$fold$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$box$1$invokeSuspend$$inlined$fold$1 @@ -173,11 +199,19 @@ public final class CrossinlineKt$consumeEach$2 { inner class CrossinlineKt$consumeEach$2$send$1 public method (p0: kotlin.jvm.functions.Function2): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$filter$$inlined$source$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object + field L$5: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1 @@ -188,7 +222,12 @@ public final class CrossinlineKt$filter$$inlined$source$1$1 { } @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1 @@ -206,6 +245,7 @@ public final class CrossinlineKt$filter$$inlined$source$1$lambda$1 { inner class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 public method (p0: Sink, p1: CrossinlineKt$filter$$inlined$source$1): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -216,6 +256,7 @@ public final class CrossinlineKt$filter$$inlined$source$1 { inner class CrossinlineKt$filter$$inlined$source$1 inner class CrossinlineKt$filter$$inlined$source$1$1 public method (p0: SourceCrossinline, p1: kotlin.jvm.functions.Function1): void + public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -238,6 +279,7 @@ public final class CrossinlineKt$fold$$inlined$consumeEach$1 { inner class CrossinlineKt$fold$$inlined$consumeEach$1$1 public method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -271,7 +313,11 @@ public final class CrossinlineKt$range$$inlined$source$1 { } @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$source$1$consume$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$source$1 @@ -287,6 +333,7 @@ public final class CrossinlineKt$source$1 { inner class CrossinlineKt$source$1 inner class CrossinlineKt$source$1$consume$1 public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt index 797b1d7e560..972ee4b2f66 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt @@ -56,6 +56,11 @@ public final class CrossinlineKt$box$1$doResume$$inlined$filter$1 { @kotlin.Metadata public final class CrossinlineKt$box$1$doResume$$inlined$fold$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$box$1$doResume$$inlined$fold$1 @@ -79,6 +84,12 @@ public final class CrossinlineKt$box$1$doResume$$inlined$fold$1 { @kotlin.Metadata public final class CrossinlineKt$box$1$filter$$inlined$source$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object + field L$5: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1 @@ -92,6 +103,10 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$1 { @kotlin.Metadata public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1 @@ -111,6 +126,7 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1 { inner class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 public method (p0: Sink, p1: CrossinlineKt$box$1$filter$$inlined$source$1): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -121,11 +137,17 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1 { inner class CrossinlineKt$box$1$filter$$inlined$source$1 inner class CrossinlineKt$box$1$filter$$inlined$source$1$1 public method (p0: SourceCrossinline, p1: kotlin.jvm.functions.Function1): void + public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @kotlin.Metadata public final class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$box$1$fold$$inlined$consumeEach$1 @@ -145,6 +167,7 @@ public final class CrossinlineKt$box$1$fold$$inlined$consumeEach$1 { inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1 public method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -183,11 +206,18 @@ public final class CrossinlineKt$consumeEach$2 { inner class CrossinlineKt$consumeEach$2$send$1 public method (p0: kotlin.jvm.functions.Function2): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @kotlin.Metadata public final class CrossinlineKt$filter$$inlined$source$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object + field L$4: java.lang.Object + field L$5: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1 @@ -201,6 +231,10 @@ public final class CrossinlineKt$filter$$inlined$source$1$1 { @kotlin.Metadata public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1 @@ -220,6 +254,7 @@ public final class CrossinlineKt$filter$$inlined$source$1$lambda$1 { inner class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 public method (p0: Sink, p1: CrossinlineKt$filter$$inlined$source$1): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -230,6 +265,7 @@ public final class CrossinlineKt$filter$$inlined$source$1 { inner class CrossinlineKt$filter$$inlined$source$1 inner class CrossinlineKt$filter$$inlined$source$1$1 public method (p0: SourceCrossinline, p1: kotlin.jvm.functions.Function1): void + public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -254,6 +290,7 @@ public final class CrossinlineKt$fold$$inlined$consumeEach$1 { inner class CrossinlineKt$fold$$inlined$consumeEach$1$1 public method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void + public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -289,6 +326,9 @@ public final class CrossinlineKt$range$$inlined$source$1 { @kotlin.Metadata public final class CrossinlineKt$source$1$consume$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: CrossinlineKt$source$1 @@ -306,6 +346,7 @@ public final class CrossinlineKt$source$1 { inner class CrossinlineKt$source$1 inner class CrossinlineKt$source$1$consume$1 public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method consume$$forInline(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.txt index 4efa4f7c703..c3268eca4e3 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.txt @@ -64,6 +64,10 @@ public final class flow/InnerObjectRetransformationKt$check$$inlined$flow$1 { @kotlin.Metadata public final class flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$flowWith$1 @@ -110,6 +114,7 @@ public final class flow/InnerObjectRetransformationKt$collect$2 { inner class flow/InnerObjectRetransformationKt$collect$2 inner class flow/InnerObjectRetransformationKt$collect$2$emit$1 public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method emit$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method emit(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -130,6 +135,7 @@ public final class flow/InnerObjectRetransformationKt$flow$1 { inner class flow/InnerObjectRetransformationKt$flow$1 inner class flow/InnerObjectRetransformationKt$flow$1$collect$1 public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @@ -151,11 +157,17 @@ public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 { inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1$1 public method (p0: flow.Flow, p1: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } @kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$2 @@ -172,6 +184,7 @@ public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2 { inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2 inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2$1 public method (p0: flow.Flow, p1: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_1_2.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_1_2.txt index f158e59d625..2bdb79ad62a 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_1_2.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_1_2.txt @@ -65,6 +65,10 @@ public final class flow/InnerObjectRetransformationKt$check$$inlined$flow$1 { @kotlin.Metadata public final class flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$flowWith$1 @@ -116,6 +120,7 @@ public final class flow/InnerObjectRetransformationKt$collect$2 { inner class flow/InnerObjectRetransformationKt$collect$2 inner class flow/InnerObjectRetransformationKt$collect$2$emit$1 public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method emit$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method emit(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -138,6 +143,7 @@ public final class flow/InnerObjectRetransformationKt$flow$1 { inner class flow/InnerObjectRetransformationKt$flow$1 inner class flow/InnerObjectRetransformationKt$flow$1$collect$1 public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @@ -161,11 +167,16 @@ public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 { inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1$1 public method (p0: flow.Flow, p1: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } @kotlin.Metadata public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field L$3: java.lang.Object synthetic field data: java.lang.Object synthetic field exception: java.lang.Throwable synthetic final field this$0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$2 @@ -184,6 +195,7 @@ public final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2 { inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2 inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2$1 public method (p0: flow.Flow, p1: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } diff --git a/compiler/testData/codegen/bytecodeListing/coroutineFields.txt b/compiler/testData/codegen/bytecodeListing/coroutineFields.txt index 73e6bf70ecc..23cf146a2fd 100644 --- a/compiler/testData/codegen/bytecodeListing/coroutineFields.txt +++ b/compiler/testData/codegen/bytecodeListing/coroutineFields.txt @@ -41,6 +41,7 @@ final class CoroutineFieldsKt$box$1 { field J$0: long field L$0: java.lang.Object field L$1: java.lang.Object + field L$2: java.lang.Object private field p$: Controller inner class CoroutineFieldsKt$box$1 method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: COROUTINES_PACKAGE.Continuation): void diff --git a/compiler/testData/codegen/bytecodeListing/coroutineFields_1_3.txt b/compiler/testData/codegen/bytecodeListing/coroutineFields_1_3.txt index b2500d9f9fd..415b4922670 100644 --- a/compiler/testData/codegen/bytecodeListing/coroutineFields_1_3.txt +++ b/compiler/testData/codegen/bytecodeListing/coroutineFields_1_3.txt @@ -40,6 +40,7 @@ final class CoroutineFieldsKt$box$1 { field J$0: long field L$0: java.lang.Object field L$1: java.lang.Object + field L$2: java.lang.Object field label: int private field p$: Controller inner class CoroutineFieldsKt$box$1 diff --git a/compiler/testData/codegen/bytecodeText/boxing/crossinlineSuspend.kt b/compiler/testData/codegen/bytecodeText/boxing/crossinlineSuspend.kt index 83831e76407..3fc28b1bda5 100644 --- a/compiler/testData/codegen/bytecodeText/boxing/crossinlineSuspend.kt +++ b/compiler/testData/codegen/bytecodeText/boxing/crossinlineSuspend.kt @@ -6,5 +6,8 @@ inline fun inlineMe(crossinline c: suspend () -> Int): suspend () -> Int { return i } +// invokeSuspend$$forInline : valueOf +// invokeSuspend : boxInt + // 1 valueOf -// 0 boxInt +// 1 boxInt diff --git a/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt b/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt index e7d05f269bf..9cddea32b95 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt @@ -14,8 +14,8 @@ fun main(args: Array) { @BuilderInference suspend fun SequenceScope.awaitSeq(): Int = 42 -// 1 LOCALVARIABLE a I L16 L.* 3 -// 1 LINENUMBER 8 L16 +// 1 LOCALVARIABLE a I L17 L.* 3 +// 1 LINENUMBER 8 L17 // Adding ignore flags below the test since the test relies on line numbers. // IGNORE_BACKEND: JVM_IR diff --git a/compiler/testData/codegen/bytecodeText/coroutines/stateMachine/withTypeParameter.kt b/compiler/testData/codegen/bytecodeText/coroutines/stateMachine/withTypeParameter.kt index 18048b2aa80..d7feb7fbb55 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/stateMachine/withTypeParameter.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/stateMachine/withTypeParameter.kt @@ -21,4 +21,6 @@ class Test { } } -// 4 TABLESWITCH \ No newline at end of file +// suspend lambdas: 4 +// suspend lambdas $$forInline: 1 +// 5 TABLESWITCH \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7e66ddbe5ab..75f1f7932ac 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7381,6 +7381,43 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/javaInterop") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaInterop extends AbstractBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception { + KotlinTestUtils.runTest(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInJavaInterop() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/javaInterop"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines"); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8a10d1bc224..94f23f67c69 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -7381,6 +7381,43 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/coroutines/javaInterop") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaInterop extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception { + KotlinTestUtils.runTest(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInJavaInterop() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/javaInterop"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines"); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 92e1567aa9f..32745e88ec8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7381,6 +7381,43 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @TestMetadata("compiler/testData/codegen/box/coroutines/javaInterop") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaInterop extends AbstractIrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception { + KotlinTestUtils.runTest(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInJavaInterop() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/javaInterop"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines"); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 2655a7d5bd9..90e1cf1e246 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -5701,6 +5701,33 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/javaInterop") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaInterop extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception { + KotlinTestUtils.runTest0(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInJavaInterop() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/javaInterop"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines"); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 01496dd0ee7..028a7c05623 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6441,6 +6441,43 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/javaInterop") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaInterop extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception { + KotlinTestUtils.runTest0(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInJavaInterop() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/javaInterop"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnLambda.kt") + public void testReturnLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("returnObject.kt") + public void testReturnObject_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/javaInterop/returnObject.kt", "kotlin.coroutines"); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)