From 0fec3470dd075077006e0e09933ea55de8227e3c Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Thu, 14 Mar 2019 17:50:28 +0300 Subject: [PATCH] Regenerate anonymous object if call site of non-inlineable functional argument is suspend Split LambdaInfo into inlineable and non-inlineable #KT-26925 --- .../jetbrains/kotlin/codegen/CallGenerator.kt | 3 +- .../binding/CodegenAnnotatingVisitor.java | 5 +- .../codegen/binding/CodegenBinding.java | 5 +- .../inline/AnonymousObjectTransformer.kt | 26 +++---- .../codegen/inline/CapturedParamInfo.java | 2 +- .../kotlin/codegen/inline/InlineCodegen.kt | 30 ++++++-- .../kotlin/codegen/inline/InliningContext.kt | 6 +- .../kotlin/codegen/inline/InvokeCall.java | 6 +- .../kotlin/codegen/inline/LambdaInfo.kt | 7 +- .../kotlin/codegen/inline/MethodInliner.kt | 45 ++++++------ .../codegen/inline/MethodInlinerUtil.kt | 41 +++++------ .../kotlin/codegen/inline/ParameterInfo.java | 10 +-- .../codegen/inline/ParametersBuilder.kt | 6 +- .../inline/RegeneratedLambdaFieldRemapper.kt | 2 +- .../codegen/inline/TransformationInfo.kt | 4 +- .../inline/coroutines/CoroutineTransformer.kt | 13 ++-- .../codegen/inline/transformationUtils.kt | 2 +- .../backend/jvm/codegen/IrInlineCodegen.kt | 2 +- .../suspend/nonSuspendCrossinline.kt | 64 +++++++++++++++++ .../crossingCoroutineBoundaries.kt | 61 ++++++++++++++++ .../suspend/stateMachine/independentInline.kt | 69 +++++++++++++++++++ .../suspend/stateMachine/passParameter.kt | 60 ++++++++++++++++ .../stateMachine/passParameterLambda.kt | 36 ++++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 50 ++++++++++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 50 ++++++++++++++ .../IrBlackBoxInlineCodegenTestGenerated.java | 50 ++++++++++++++ .../IrInlineSuspendTestsGenerated.java | 25 +++++++ .../InlineSuspendTestsGenerated.java | 50 ++++++++++++++ 28 files changed, 633 insertions(+), 97 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt index a28166cad5d..fba6b675eb5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt @@ -18,7 +18,8 @@ enum class ValueKind { DEFAULT_MASK, METHOD_HANDLE_IN_DEFAULT, CAPTURED, - DEFAULT_LAMBDA_CAPTURED_PARAMETER + DEFAULT_LAMBDA_CAPTURED_PARAMETER, + NON_INLINEABLE_CALLED_IN_SUSPEND } interface CallGenerator { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index 40775ef0062..c41ed92b1fe 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -726,6 +726,9 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { if (variableDescriptor instanceof ValueParameterDescriptor && ((ValueParameterDescriptor) variableDescriptor).isCrossinline()) { DeclarationDescriptor functionWithCrossinlineParameter = variableDescriptor.getContainingDeclaration(); + if (functionsStack.peek().isSuspend()) { + bindingTrace.record(CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, (ValueParameterDescriptor) variableDescriptor, true); + } for (int i = functionsStack.size() - 1; i >= 0; i--) { Boolean alreadyPutValue = bindingTrace.getBindingContext() .get(CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA, functionsStack.get(i)); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java index bb8d7705013..d90cfe47725 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2017 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. */ @@ -60,6 +60,9 @@ public class CodegenBinding { public static final WritableSlice CAPTURES_CROSSINLINE_LAMBDA = Slices.createSimpleSlice(); + public static final WritableSlice CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA = + Slices.createSimpleSlice(); + public static final WritableSlice RECURSIVE_SUSPEND_CALLABLE_REFERENCE = Slices.createSimpleSlice(); 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 0bc1f1ac628..b7ff75e8909 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -343,7 +343,7 @@ class AnonymousObjectTransformer( for (info in constructorAdditionalFakeParams) { val fake = constructorInlineBuilder.addCapturedParamCopy(info) - if (fake.lambda != null) { + if (fake.functionalArgument is LambdaInfo) { //set remap value to skip this fake (captured with lambda already skipped) val composed = StackValue.field( fake.getType(), @@ -415,7 +415,7 @@ class AnonymousObjectTransformer( ): List { val capturedLambdas = LinkedHashSet() //captured var of inlined parameter val constructorAdditionalFakeParams = ArrayList() - val indexToLambda = transformationInfo.lambdasToInline + val indexToFunctionalArgument = transformationInfo.functionalArguments val capturedParams = HashSet() //load captured parameters and patch instruction list @@ -425,18 +425,18 @@ class AnonymousObjectTransformer( val fieldName = fieldNode.name val parameterAload = fieldNode.previous as VarInsnNode val varIndex = parameterAload.`var` - val lambdaInfo = indexToLambda[varIndex] - val newFieldName = if (isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values)) + val functionalArgument = indexToFunctionalArgument[varIndex] + val newFieldName = if (isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToFunctionalArgument.values)) getNewFieldName(fieldName, true) else fieldName val info = capturedParamBuilder.addCapturedParam( Type.getObjectType(transformationInfo.oldClassName), fieldName, newFieldName, - Type.getType(fieldNode.desc), lambdaInfo != null, null + Type.getType(fieldNode.desc), functionalArgument is LambdaInfo, null ) - if (lambdaInfo != null) { - info.lambda = lambdaInfo - capturedLambdas.add(lambdaInfo) + info.functionalArgument = functionalArgument + if (functionalArgument is LambdaInfo) { + capturedLambdas.add(functionalArgument) } constructorAdditionalFakeParams.add(info) capturedParams.add(varIndex) @@ -451,9 +451,9 @@ class AnonymousObjectTransformer( val paramTypes = transformationInfo.constructorDesc?.let { Type.getArgumentTypes(it) } ?: emptyArray() for (type in paramTypes) { - val info = indexToLambda[constructorParamBuilder.nextParameterOffset] - val parameterInfo = constructorParamBuilder.addNextParameter(type, info != null) - parameterInfo.lambda = info + val info = indexToFunctionalArgument[constructorParamBuilder.nextParameterOffset] + val parameterInfo = constructorParamBuilder.addNextParameter(type, info is LambdaInfo) + parameterInfo.functionalArgument = info if (capturedParams.contains(parameterInfo.index)) { parameterInfo.isCaptured = true } else { @@ -519,9 +519,9 @@ class AnonymousObjectTransformer( return constructorAdditionalFakeParams } - private fun shouldRenameThis0(parentFieldRemapper: FieldRemapper, values: Collection): Boolean { + private fun shouldRenameThis0(parentFieldRemapper: FieldRemapper, values: Collection): Boolean { return if (isFirstDeclSiteLambdaFieldRemapper(parentFieldRemapper)) { - values.any { it.capturedVars.any { isThis0(it.fieldName) } } + values.any { it is LambdaInfo && it.capturedVars.any { isThis0(it.fieldName) } } } else false } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java index f5ec2fc5dc9..3b9ce761d5e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java @@ -65,7 +65,7 @@ public class CapturedParamInfo extends ParameterInfo { CapturedParamInfo result = new CapturedParamInfo( desc, newFieldName, isSkipped, getIndex(), getRemapValue(), skipInConstructor, newDeclarationIndex ); - result.setLambda(getLambda()); + result.setFunctionalArgument(getFunctionalArgument()); result.setSynthetic(synthetic); return result; } 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 4b05789cd34..36dc4c71ce6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.* 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.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.state.GenerationState @@ -83,7 +84,7 @@ abstract class InlineCodegen( protected val invocationParamBuilder = ParametersBuilder.newBuilder() - protected val expressionMap = linkedMapOf() + protected val expressionMap = linkedMapOf() var activeLambda: LambdaInfo? = null protected set @@ -234,7 +235,7 @@ abstract class InlineCodegen( extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor) ) for (lambda in defaultLambdas) { - invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).lambda = lambda + invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).functionalArgument = lambda val prev = expressionMap.put(lambda.offset, lambda) assert(prev == null) { "Lambda with offset ${lambda.offset} already exists: $prev" } } @@ -310,7 +311,9 @@ abstract class InlineCodegen( private fun generateClosuresBodies() { for (info in expressionMap.values) { - info.generateLambdaBody(sourceCompiler, reifiedTypeInliner) + if (info is LambdaInfo) { + info.generateLambdaBody(sourceCompiler, reifiedTypeInliner) + } } } @@ -340,6 +343,9 @@ abstract class InlineCodegen( info.setRemapValue(remappedValue) } else { info = invocationParamBuilder.addNextValueParameter(jvmType, false, remappedValue, parameterIndex) + if (kind == ValueKind.NON_INLINEABLE_CALLED_IN_SUSPEND) { + info.functionalArgument = CrossinlineLambdaInSuspendContextAsNoInline + } } recordParameterValueInLocalVal( @@ -395,8 +401,10 @@ abstract class InlineCodegen( private fun putClosureParametersOnStack() { for (next in expressionMap.values) { //closure parameters for bounded callable references are generated inplace - if (next is ExpressionLambda && next.isBoundCallableReference) continue - putClosureParametersOnStack(next, null) + if (next is LambdaInfo) { + if (next is ExpressionLambda && next.isBoundCallableReference) continue + putClosureParametersOnStack(next, null) + } } } @@ -730,10 +738,18 @@ class PsiInlineCodegen( } } else { val value = codegen.gen(argumentExpression) - putValueIfNeeded(parameterType, value, ValueKind.GENERAL, parameterIndex) + putValueIfNeeded( + parameterType, + value, + if (isCallSiteIsSuspend(valueParameterDescriptor)) ValueKind.NON_INLINEABLE_CALLED_IN_SUSPEND else ValueKind.GENERAL, + parameterIndex + ) } } + private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean = + state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true + private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { val ktLambda = KtPsiUtil.deparenthesize(expression) assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } @@ -743,7 +759,7 @@ class PsiInlineCodegen( parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null ).also { lambda -> val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) - closureInfo.lambda = lambda + closureInfo.functionalArgument = lambda expressionMap.put(closureInfo.index, lambda) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt index afa4b20521a..2737b651717 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.state.GenerationState class RootInliningContext( - expressionMap: Map, + expressionMap: Map, state: GenerationState, nameGenerator: NameGenerator, val sourceCompilerForInline: SourceCompilerForInline, @@ -22,7 +22,7 @@ class RootInliningContext( class RegeneratedClassContext( parent: InliningContext, - expressionMap: Map, + expressionMap: Map, state: GenerationState, nameGenerator: NameGenerator, typeRemapper: TypeRemapper, @@ -36,7 +36,7 @@ class RegeneratedClassContext( open class InliningContext( val parent: InliningContext?, - val expressionMap: Map, + val expressionMap: Map, val state: GenerationState, val nameGenerator: NameGenerator, val typeRemapper: TypeRemapper, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java index c5ad2000797..747d30ec160 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java @@ -19,11 +19,11 @@ package org.jetbrains.kotlin.codegen.inline; import org.jetbrains.annotations.Nullable; class InvokeCall { - public final LambdaInfo lambdaInfo; + public final FunctionalArgument functionalArgument; public final int finallyDepthShift; - InvokeCall(@Nullable LambdaInfo lambdaInfo, int finallyDepthShift) { - this.lambdaInfo = lambdaInfo; + InvokeCall(@Nullable FunctionalArgument functionalArgument, int finallyDepthShift) { + this.functionalArgument = functionalArgument; this.finallyDepthShift = finallyDepthShift; } } 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 f47692bb2a8..157222f01b5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-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. */ @@ -35,7 +35,9 @@ import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode import org.jetbrains.org.objectweb.asm.tree.MethodNode import kotlin.properties.Delegates -abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : LabelOwner { +interface FunctionalArgument + +abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgument, LabelOwner { abstract val isBoundCallableReference: Boolean @@ -77,6 +79,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : LabelOwner { } } +object CrossinlineLambdaInSuspendContextAsNoInline : FunctionalArgument class DefaultLambda( override val lambdaClassType: Type, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 3ea47f61b0f..1b9df821228 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -217,9 +217,9 @@ class MethodInliner( if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnLambda(owner, name)) { //TODO add method assert(!currentInvokes.isEmpty()) val invokeCall = currentInvokes.remove() - val info = invokeCall.lambdaInfo + val info = invokeCall.functionalArgument - if (info == null) { + if (info !is LambdaInfo) { //noninlinable lambda super.visitMethodInsn(opcode, owner, name, desc, itf) return @@ -263,7 +263,7 @@ class MethodInliner( listOf(*info.invokeMethod.argumentTypes), valueParameters, invokeParameters, valueParamShift, this, coroutineDesc ) - if (invokeCall.lambdaInfo.invokeMethodDescriptor.valueParameters.isEmpty()) { + if (info.invokeMethodDescriptor.valueParameters.isEmpty()) { // There won't be no parameters processing and line call can be left without actual instructions. // Note: if function is called on the line with other instructions like 1 + foo(), 'nop' will still be generated. visitInsn(Opcodes.NOP) @@ -447,7 +447,7 @@ class MethodInliner( override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) { if (DEFAULT_LAMBDA_FAKE_CALL == owner) { val index = name.substringAfter(DEFAULT_LAMBDA_FAKE_CALL).toInt() - val lambda = getLambdaIfExists(index) as DefaultLambda + val lambda = getFunctionalArgumentIfExists(index) as DefaultLambda lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach { (_, captured) -> val originalBoundReceiverType = lambda.originalBoundReceiverType if (lambda.isBoundCallableReference && AsmUtil.isPrimitive(originalBoundReceiverType)) { @@ -522,22 +522,23 @@ class MethodInliner( val firstParameterIndex = frame.stackSize - paramCount if (isInvokeOnLambda(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { val sourceValue = frame.getStack(firstParameterIndex) - val lambdaInfo = getLambdaIfExistsAndMarkInstructions(sourceValue, true, instructions, sources, toDelete) - invokeCalls.add(InvokeCall(lambdaInfo, currentFinallyDeep)) + val functionalArgument = + getFunctionalArgumentIfExistsAndMarkInstructions(sourceValue, true, instructions, sources, toDelete) + invokeCalls.add(InvokeCall(functionalArgument, currentFinallyDeep)) } else if (isSamWrapperConstructorCall(owner, name)) { recordTransformation(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner))) } else if (isAnonymousConstructorCall(owner, name)) { - val lambdaMapping = HashMap() + val functionalArgumentMapping = HashMap() var offset = 0 var capturesAnonymousObjectThatMustBeRegenerated = false for (i in 0 until paramCount) { val sourceValue = frame.getStack(firstParameterIndex + i) - val lambdaInfo = getLambdaIfExistsAndMarkInstructions( + val functionalArgument = getFunctionalArgumentIfExistsAndMarkInstructions( sourceValue, false, instructions, sources, toDelete ) - if (lambdaInfo != null) { - lambdaMapping.put(offset, lambdaInfo) + if (functionalArgument != null) { + functionalArgumentMapping.put(offset, functionalArgument) } else if (i < argTypes.size && isAnonymousClassThatMustBeRegenerated(argTypes[i])) { capturesAnonymousObjectThatMustBeRegenerated = true } @@ -547,7 +548,7 @@ class MethodInliner( recordTransformation( buildConstructorInvocation( - owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated + owner, cur.desc, functionalArgumentMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated ) ) awaitClassReification = false @@ -595,14 +596,16 @@ class MethodInliner( } } - cur.opcode == Opcodes.POP -> getLambdaIfExistsAndMarkInstructions( + cur.opcode == Opcodes.POP -> getFunctionalArgumentIfExistsAndMarkInstructions( frame.top()!!, true, instructions, sources, toDelete )?.let { - toDelete.add(cur) + if (it is LambdaInfo) { + toDelete.add(cur) + } } cur.opcode == Opcodes.PUTFIELD -> { @@ -620,8 +623,8 @@ class MethodInliner( ) { val stackTransformations = mutableSetOf() val lambdaInfo = - getLambdaIfExistsAndMarkInstructions(frame.peek(1)!!, false, instructions, sources, stackTransformations) - if (lambdaInfo != null && stackTransformations.all { it is VarInsnNode }) { + getFunctionalArgumentIfExistsAndMarkInstructions(frame.peek(1)!!, false, instructions, sources, stackTransformations) + if (lambdaInfo is LambdaInfo && stackTransformations.all { it is VarInsnNode }) { assert(lambdaInfo.lambdaClassType.internalName == nodeRemapper.originalLambdaInternalName) { "Wrong bytecode template for contract template: ${lambdaInfo.lambdaClassType.internalName} != ${nodeRemapper.originalLambdaInternalName}" } @@ -812,7 +815,7 @@ class MethodInliner( private fun buildConstructorInvocation( anonymousType: String, desc: String, - lambdaMapping: Map, + lambdaMapping: Map, needReification: Boolean, capturesAnonymousObjectThatMustBeRegenerated: Boolean ): AnonymousObjectTransformationInfo { @@ -845,20 +848,20 @@ class MethodInliner( return inliningContext.typeRemapper.hasNoAdditionalMapping(owner) } - internal fun getLambdaIfExists(insnNode: AbstractInsnNode): LambdaInfo? { + internal fun getFunctionalArgumentIfExists(insnNode: AbstractInsnNode): FunctionalArgument? { return when { insnNode.opcode == Opcodes.ALOAD -> - getLambdaIfExists((insnNode as VarInsnNode).`var`) + getFunctionalArgumentIfExists((insnNode as VarInsnNode).`var`) insnNode is FieldInsnNode && insnNode.name.startsWith(CAPTURED_FIELD_FOLD_PREFIX) -> - findCapturedField(insnNode, nodeRemapper).lambda + findCapturedField(insnNode, nodeRemapper).functionalArgument else -> null } } - private fun getLambdaIfExists(varIndex: Int): LambdaInfo? { + private fun getFunctionalArgumentIfExists(varIndex: Int): FunctionalArgument? { if (varIndex < parameters.argsSizeOnStack) { - return parameters.getParameterByDeclarationSlot(varIndex).lambda + return parameters.getParameterByDeclarationSlot(varIndex).functionalArgument } return null } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt index 24d53c77ef0..863d929792a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt @@ -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 @@ -26,37 +15,39 @@ import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue -fun MethodInliner.getLambdaIfExistsAndMarkInstructions( +fun MethodInliner.getFunctionalArgumentIfExistsAndMarkInstructions( sourceValue: SourceValue, processSwap: Boolean, insnList: InsnList, frames: Array?>, toDelete: MutableSet -): LambdaInfo? { +): FunctionalArgument? { val toDeleteInner = SmartSet.create() - val lambdaSet = SmartSet.create() - sourceValue.insns.mapTo(lambdaSet) { - getLambdaIfExistsAndMarkInstructions(it, processSwap, insnList, frames, toDeleteInner) + val functionalArgumentSet = SmartSet.create() + sourceValue.insns.mapTo(functionalArgumentSet) { + getFunctionalArgumentIfExistsAndMarkInstructions(it, processSwap, insnList, frames, toDeleteInner) } - return lambdaSet.singleOrNull()?.also { - toDelete.addAll(toDeleteInner) + return functionalArgumentSet.singleOrNull()?.also { + if (it is LambdaInfo) { + toDelete.addAll(toDeleteInner) + } } } private fun SourceValue.singleOrNullInsn() = insns.singleOrNull() -private fun MethodInliner.getLambdaIfExistsAndMarkInstructions( +private fun MethodInliner.getFunctionalArgumentIfExistsAndMarkInstructions( insnNode: AbstractInsnNode?, processSwap: Boolean, insnList: InsnList, frames: Array?>, toDelete: MutableSet -): LambdaInfo? { +): FunctionalArgument? { if (insnNode == null) return null - getLambdaIfExists(insnNode)?.let { + getFunctionalArgumentIfExists(insnNode)?.let { //delete lambda aload instruction toDelete.add(insnNode) return it @@ -69,7 +60,7 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions( if (storeIns is VarInsnNode && storeIns.getOpcode() == Opcodes.ASTORE) { val frame = frames[insnList.indexOf(storeIns)] ?: return null val topOfStack = frame.top()!! - getLambdaIfExistsAndMarkInstructions(topOfStack, processSwap, insnList, frames, toDelete)?.let { + getFunctionalArgumentIfExistsAndMarkInstructions(topOfStack, processSwap, insnList, frames, toDelete)?.let { //remove intermediate lambda astore, aload instruction: see 'complexStack/simple.1.kt' test toDelete.add(storeIns) toDelete.add(insnNode) @@ -79,7 +70,7 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions( } else if (processSwap && insnNode.opcode == Opcodes.SWAP) { val swapFrame = frames[insnList.indexOf(insnNode)] ?: return null val dispatchReceiver = swapFrame.top()!! - getLambdaIfExistsAndMarkInstructions(dispatchReceiver, false, insnList, frames, toDelete)?.let { + getFunctionalArgumentIfExistsAndMarkInstructions(dispatchReceiver, false, insnList, frames, toDelete)?.let { //remove swap instruction (dispatch receiver would be deleted on recursion call): see 'complexStack/simpleExtension.1.kt' test toDelete.add(insnNode) return it diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java index ab985de79dd..03640bfc712 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParameterInfo.java @@ -29,7 +29,7 @@ public class ParameterInfo { public final boolean isSkipped; private boolean isCaptured; - private LambdaInfo lambda; + private FunctionalArgument functionalArgument; //in case when parameter could be extracted from outer context (e.g. from local var) private StackValue remapValue; @@ -68,13 +68,13 @@ public class ParameterInfo { } @Nullable - public LambdaInfo getLambda() { - return lambda; + public FunctionalArgument getFunctionalArgument() { + return functionalArgument; } @NotNull - public ParameterInfo setLambda(@Nullable LambdaInfo lambda) { - this.lambda = lambda; + public ParameterInfo setFunctionalArgument(@Nullable FunctionalArgument functionalArgument) { + this.functionalArgument = functionalArgument; return this; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt index f0ee7879b48..62a90ce4ebc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt @@ -38,7 +38,7 @@ class ParametersBuilder private constructor() { fun addCapturedParam(original: CapturedParamInfo, newFieldName: String): CapturedParamInfo { val info = CapturedParamInfo(original.desc, newFieldName, original.isSkipped, nextParameterOffset, original.index) - info.lambda = original.lambda + info.functionalArgument = original.functionalArgument return addParameter(info) } @@ -62,7 +62,7 @@ class ParametersBuilder private constructor() { CapturedParamDesc(containingLambdaType, fieldName, type), newFieldName, skipped, nextParameterOffset, original?.index ?: -1 ) if (original != null) { - info.lambda = original.lambda + info.functionalArgument = original.functionalArgument } return addParameter(info) } @@ -116,7 +116,7 @@ class ParametersBuilder private constructor() { val builder = newBuilder() if (inlineLambda?.hasDispatchReceiver != false && !isStatic) { //skipped this for inlined lambda cause it will be removed - builder.addThis(objectType, inlineLambda != null).lambda = inlineLambda + builder.addThis(objectType, inlineLambda != null).functionalArgument = inlineLambda } for (type in Type.getArgumentTypes(descriptor)) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegeneratedLambdaFieldRemapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegeneratedLambdaFieldRemapper.kt index 34faa979abf..f6ed38a027d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegeneratedLambdaFieldRemapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegeneratedLambdaFieldRemapper.kt @@ -75,7 +75,7 @@ class RegeneratedLambdaFieldRemapper( val result = StackValue.field( - if (field.isSkipped) + if (field.isSkipped && field.functionalArgument is LambdaInfo) Type.getObjectType(parent!!.parent!!.newLambdaInternalName) else field.getType(), diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TransformationInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TransformationInfo.kt index 141a5cd4f17..54a28a963c6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TransformationInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TransformationInfo.kt @@ -67,7 +67,7 @@ class WhenMappingTransformationInfo( class AnonymousObjectTransformationInfo internal constructor( override val oldClassName: String, private val needReification: Boolean, - val lambdasToInline: Map, + val functionalArguments: Map, private val capturedOuterRegenerated: Boolean, private val alreadyRegenerated: Boolean, val constructorDesc: String?, @@ -99,7 +99,7 @@ class AnonymousObjectTransformationInfo internal constructor( override fun shouldRegenerate(sameModule: Boolean): Boolean = !alreadyRegenerated && - (!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated) + (!functionalArguments.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated) override fun canRemoveAfterTransformation(): Boolean { // Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda 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 af3381918d4..90a9777c79a 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 @@ -18,7 +18,6 @@ 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 -import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode import org.jetbrains.org.objectweb.asm.tree.MethodNode @@ -38,14 +37,14 @@ class CoroutineTransformer( // See innerObjectRetransformation.kt if (inliningContext.callSiteInfo.isInlineOrInsideInline) return false if (isContinuationNotLambda()) return false - val crossinlineParam = crossinlineLambda() ?: 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 + crossinlineParam?.invokeMethodDescriptor?.containingDeclaration as? FunctionDescriptor ?: return true !functionDescriptor.isInline } else -> false @@ -66,9 +65,11 @@ class CoroutineTransformer( private fun isSuspendLambda(node: MethodNode) = isResumeImpl(node) fun newMethod(node: MethodNode): DeferredMethodVisitor { - val element = crossinlineLambda()?.functionWithBodyOrCallableReference.sure { - "crossinline lambda should have element" - } + // Find ANY element to report error about suspension point in monitor on. + val element = crossinlineLambda()?.functionWithBodyOrCallableReference + ?: inliningContext.root.sourceCompilerForInline.callElement as? KtElement + ?: error("crossinline lambda should have element") + return when { isResumeImpl(node) -> { assert(!isStateMachine(node)) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt index dd8b2ded9a6..59b2809a9b3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt @@ -25,7 +25,7 @@ class NewJavaField(val name: String, val type: Type, val skip: Boolean) fun getNewFieldsToGenerate(params: List): List { return params.filter { //not inlined - it.lambda == null + it.functionalArgument !is LambdaInfo }.map { NewJavaField(it.newFieldName, it.type, it.isSkipInConstructor) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index b4dbb442f98..a707ef40ee7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -99,7 +99,7 @@ class IrInlineCodegen( parameter.type.isExtensionFunctionType ).also { lambda -> val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) - closureInfo.lambda = lambda + closureInfo.functionalArgument = lambda expressionMap[closureInfo.index] = lambda } } diff --git a/compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt b/compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt new file mode 100644 index 00000000000..a9e11c4dc89 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt @@ -0,0 +1,64 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_STATE_MACHINE + +// FILE: inline.kt + +class MyDeferred(val t: suspend () -> T) { + suspend fun await() = t() +} + +fun async(block: suspend () -> T) = MyDeferred(block) + +inline fun map(source: MyDeferred, crossinline mapper: (T) -> R) = + async { + mapper(source.await()) + } + +inline fun map2(source: MyDeferred, crossinline mapper1: (T) -> R1, crossinline mapper2: (R1) -> R2) = + async { + val c = suspend { + mapper1(source.await()) + } + mapper2(c()) + } + +inline fun map3(source: MyDeferred, crossinline mapper1: (T) -> R1, crossinline mapper2: (R1) -> R2, crossinline mapper3: (R2) -> R3) = + async { + val c = suspend { + val c = suspend { + mapper1(source.await()) + } + mapper2(c()) + } + mapper3(c()) + } + +// FILE: box.kt + +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + val source = MyDeferred { 1 } + var result = -1 + builder { + result = map(source) { it + 2 }.await() + } + if (result != 3) return "FAIL 1 $result" + builder { + result = map2(source, { it + 2 }, { it + 3 }).await() + } + if (result != 6) return "FAIL 2 $result" + builder { + result = map3(source, { it + 2 }, { it + 3 }, { it + 4 }).await() + } + if (result != 10) return "FAIL 3 $result" + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt new file mode 100644 index 00000000000..68bdb1528e1 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt @@ -0,0 +1,61 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_STATE_MACHINE + +// FILE: inline.kt + +import helpers.* +import COROUTINES_PACKAGE.* + +interface SuspendRunnable { + suspend fun run() +} + +fun runSuspend(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +inline suspend fun inlineMe(crossinline c1: suspend () -> Unit) { + object : SuspendRunnable { + override suspend fun run() { + c1() + } + }.run() + + StateMachineChecker.check(2) + StateMachineChecker.reset() + + runSuspend { + object : SuspendRunnable { + override suspend fun run() { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + } + }.run() + + StateMachineChecker.check(2) + } +} + + +// FILE: box.kt +// COMMON_COROUTINES_TEST + +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + builder { + inlineMe { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + } + } + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt new file mode 100644 index 00000000000..51765ab49cd --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt @@ -0,0 +1,69 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_STATE_MACHINE + +// FILE: inline.kt + +import helpers.* + +interface SuspendRunnable { + suspend fun run() + suspend fun ownIndependentInline() +} + +inline fun inlineMe(crossinline c1: suspend () -> Unit) = + object : SuspendRunnable { + override suspend fun run() { + c1() + c1() + } + + override suspend fun ownIndependentInline() { + inlineMe2 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + }.ownIndependentInline() + } + } + + +inline fun inlineMe2(crossinline c2: suspend () -> Unit): SuspendRunnable = + object : SuspendRunnable { + override suspend fun run() { + } + + override suspend fun ownIndependentInline() { + c2() + c2() + } + } + +// FILE: box.kt +// COMMON_COROUTINES_TEST + +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + val r = inlineMe { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + } + + builder { + r.run() + } + StateMachineChecker.check(numberOfSuspensions = 4) + StateMachineChecker.reset() + builder { + r.ownIndependentInline() + } + StateMachineChecker.check(numberOfSuspensions = 4) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt new file mode 100644 index 00000000000..0c7351c18ca --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt @@ -0,0 +1,60 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_STATE_MACHINE + +// FILE: inline.kt + +import helpers.* + +interface SuspendRunnable { + suspend fun run() + suspend fun run2() +} + +inline fun inlineMe(crossinline c1: suspend () -> Unit, crossinline c2: suspend () -> Unit) = + object : SuspendRunnable { + override suspend fun run() { + c1() // TODO: Double this call, when suspend markers are generated for inline and crossinline lambdas + } + + override suspend fun run2() { + c2() + } + } + + +inline fun inlineMe2(crossinline c1: suspend () -> Unit) = + inlineMe(c1) { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + } + +// FILE: box.kt +// COMMON_COROUTINES_TEST + +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + val r = inlineMe2 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + } + + builder { + r.run() + } + StateMachineChecker.check(numberOfSuspensions = 2) + StateMachineChecker.reset() + builder { + r.run2() + } + StateMachineChecker.check(numberOfSuspensions = 2) + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt new file mode 100644 index 00000000000..46aad02b768 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt @@ -0,0 +1,36 @@ +// IGNORE_BACKEND: JVM_IR +// COMMON_COROUTINES_TEST +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_STATE_MACHINE + +// FILE: inline.kt + +import helpers.* + +inline fun inlineMe(crossinline c: suspend () -> Unit) = suspend { c(); c() } + +inline fun inlineMe2(crossinline c: suspend () -> Unit) = inlineMe { c(); c() } + +// FILE: box.kt +// COMMON_COROUTINES_TEST + +import helpers.* +import COROUTINES_PACKAGE.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + val r = inlineMe2 { + StateMachineChecker.suspendHere() + StateMachineChecker.suspendHere() + } + + builder { + r() + } + StateMachineChecker.check(numberOfSuspensions = 8) + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 020116e6e4e..bee8770e61f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3540,6 +3540,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt", "kotlin.coroutines"); } + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines"); + } + @TestMetadata("returnValue.kt") public void testReturnValue_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/returnValue.kt", "kotlin.coroutines.experimental"); @@ -3761,6 +3771,26 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines"); + } + @TestMetadata("innerLambdaInsideLambda.kt") public void testInnerLambdaInsideLambda_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt", "kotlin.coroutines.experimental"); @@ -3910,6 +3940,26 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo public void testOneInlineTwoCaptures_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines"); } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines"); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 04c49e7ca00..48e25997368 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3540,6 +3540,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt", "kotlin.coroutines"); } + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines"); + } + @TestMetadata("returnValue.kt") public void testReturnValue_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/returnValue.kt", "kotlin.coroutines.experimental"); @@ -3761,6 +3771,26 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines"); + } + @TestMetadata("innerLambdaInsideLambda.kt") public void testInnerLambdaInsideLambda_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt", "kotlin.coroutines.experimental"); @@ -3910,6 +3940,26 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi public void testOneInlineTwoCaptures_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines"); } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines"); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 41c7c59578e..222b84e87fd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3540,6 +3540,16 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt", "kotlin.coroutines"); } + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines"); + } + @TestMetadata("returnValue.kt") public void testReturnValue_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/returnValue.kt", "kotlin.coroutines.experimental"); @@ -3761,6 +3771,26 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines"); + } + @TestMetadata("innerLambdaInsideLambda.kt") public void testInnerLambdaInsideLambda_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt", "kotlin.coroutines.experimental"); @@ -3910,6 +3940,26 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli public void testOneInlineTwoCaptures_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines"); } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines"); + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrInlineSuspendTestsGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrInlineSuspendTestsGenerated.java index 253019b9897..466c77f0c6d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrInlineSuspendTestsGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrInlineSuspendTestsGenerated.java @@ -98,6 +98,11 @@ public class IrInlineSuspendTestsGenerated extends AbstractIrInlineSuspendTests runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt", "kotlin.coroutines"); } + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines"); + } + @TestMetadata("returnValue.kt") public void testReturnValue_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/returnValue.kt", "kotlin.coroutines"); @@ -259,6 +264,16 @@ public class IrInlineSuspendTestsGenerated extends AbstractIrInlineSuspendTests KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); } + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines"); + } + @TestMetadata("innerLambdaInsideLambda.kt") public void testInnerLambdaInsideLambda_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt", "kotlin.coroutines"); @@ -333,5 +348,15 @@ public class IrInlineSuspendTestsGenerated extends AbstractIrInlineSuspendTests public void testOneInlineTwoCaptures_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines"); } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines"); + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineSuspendTestsGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineSuspendTestsGenerated.java index 76fd53f1e3f..5023e4f1b77 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineSuspendTestsGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineSuspendTestsGenerated.java @@ -158,6 +158,16 @@ public class InlineSuspendTestsGenerated extends AbstractInlineSuspendTests { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt", "kotlin.coroutines"); } + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("nonSuspendCrossinline.kt") + public void testNonSuspendCrossinline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/nonSuspendCrossinline.kt", "kotlin.coroutines"); + } + @TestMetadata("returnValue.kt") public void testReturnValue_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/returnValue.kt", "kotlin.coroutines.experimental"); @@ -379,6 +389,26 @@ public class InlineSuspendTestsGenerated extends AbstractInlineSuspendTests { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("crossingCoroutineBoundaries.kt") + public void testCrossingCoroutineBoundaries_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt", "kotlin.coroutines"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("independentInline.kt") + public void testIndependentInline_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt", "kotlin.coroutines"); + } + @TestMetadata("innerLambdaInsideLambda.kt") public void testInnerLambdaInsideLambda_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt", "kotlin.coroutines.experimental"); @@ -528,5 +558,25 @@ public class InlineSuspendTestsGenerated extends AbstractInlineSuspendTests { public void testOneInlineTwoCaptures_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/oneInlineTwoCaptures.kt", "kotlin.coroutines"); } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameterLambda.kt") + public void testPassParameterLambda_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameterLambda.kt", "kotlin.coroutines"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("passParameter.kt") + public void testPassParameter_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/stateMachine/passParameter.kt", "kotlin.coroutines"); + } } }