Regenerate anonymous object if call site of non-inlineable
functional argument is suspend Split LambdaInfo into inlineable and non-inlineable #KT-26925
This commit is contained in:
@@ -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 {
|
||||
|
||||
+4
-1
@@ -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));
|
||||
|
||||
@@ -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<FunctionDescriptor, Boolean> CAPTURES_CROSSINLINE_LAMBDA =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ValueParameterDescriptor, Boolean> CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ClassDescriptor, Boolean> RECURSIVE_SUSPEND_CALLABLE_REFERENCE =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
|
||||
+13
-13
@@ -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<CapturedParamInfo> {
|
||||
val capturedLambdas = LinkedHashSet<LambdaInfo>() //captured var of inlined parameter
|
||||
val constructorAdditionalFakeParams = ArrayList<CapturedParamInfo>()
|
||||
val indexToLambda = transformationInfo.lambdasToInline
|
||||
val indexToFunctionalArgument = transformationInfo.functionalArguments
|
||||
val capturedParams = HashSet<Int>()
|
||||
|
||||
//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<LambdaInfo>): Boolean {
|
||||
private fun shouldRenameThis0(parentFieldRemapper: FieldRemapper, values: Collection<FunctionalArgument>): 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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<out T : BaseExpressionCodegen>(
|
||||
|
||||
protected val invocationParamBuilder = ParametersBuilder.newBuilder()
|
||||
|
||||
protected val expressionMap = linkedMapOf<Int, LambdaInfo>()
|
||||
protected val expressionMap = linkedMapOf<Int, FunctionalArgument>()
|
||||
|
||||
var activeLambda: LambdaInfo? = null
|
||||
protected set
|
||||
@@ -234,7 +235,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
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<out T : BaseExpressionCodegen>(
|
||||
|
||||
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<out T : BaseExpressionCodegen>(
|
||||
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<out T : BaseExpressionCodegen>(
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
|
||||
class RootInliningContext(
|
||||
expressionMap: Map<Int, LambdaInfo>,
|
||||
expressionMap: Map<Int, FunctionalArgument>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
val sourceCompilerForInline: SourceCompilerForInline,
|
||||
@@ -22,7 +22,7 @@ class RootInliningContext(
|
||||
|
||||
class RegeneratedClassContext(
|
||||
parent: InliningContext,
|
||||
expressionMap: Map<Int, LambdaInfo>,
|
||||
expressionMap: Map<Int, FunctionalArgument>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
typeRemapper: TypeRemapper,
|
||||
@@ -36,7 +36,7 @@ class RegeneratedClassContext(
|
||||
|
||||
open class InliningContext(
|
||||
val parent: InliningContext?,
|
||||
val expressionMap: Map<Int, LambdaInfo>,
|
||||
val expressionMap: Map<Int, FunctionalArgument>,
|
||||
val state: GenerationState,
|
||||
val nameGenerator: NameGenerator,
|
||||
val typeRemapper: TypeRemapper,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<Int, LambdaInfo>()
|
||||
val functionalArgumentMapping = HashMap<Int, FunctionalArgument>()
|
||||
|
||||
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<AbstractInsnNode>()
|
||||
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<Int, LambdaInfo>,
|
||||
lambdaMapping: Map<Int, FunctionalArgument>,
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
): LambdaInfo? {
|
||||
): FunctionalArgument? {
|
||||
val toDeleteInner = SmartSet.create<AbstractInsnNode>()
|
||||
|
||||
val lambdaSet = SmartSet.create<LambdaInfo?>()
|
||||
sourceValue.insns.mapTo(lambdaSet) {
|
||||
getLambdaIfExistsAndMarkInstructions(it, processSwap, insnList, frames, toDeleteInner)
|
||||
val functionalArgumentSet = SmartSet.create<FunctionalArgument?>()
|
||||
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<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
): 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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
+1
-1
@@ -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(),
|
||||
|
||||
@@ -67,7 +67,7 @@ class WhenMappingTransformationInfo(
|
||||
class AnonymousObjectTransformationInfo internal constructor(
|
||||
override val oldClassName: String,
|
||||
private val needReification: Boolean,
|
||||
val lambdasToInline: Map<Int, LambdaInfo>,
|
||||
val functionalArguments: Map<Int, FunctionalArgument>,
|
||||
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
|
||||
|
||||
+7
-6
@@ -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)) {
|
||||
|
||||
@@ -25,7 +25,7 @@ class NewJavaField(val name: String, val type: Type, val skip: Boolean)
|
||||
fun getNewFieldsToGenerate(params: List<CapturedParamInfo>): List<NewJavaField> {
|
||||
return params.filter {
|
||||
//not inlined
|
||||
it.lambda == null
|
||||
it.functionalArgument !is LambdaInfo
|
||||
}.map {
|
||||
NewJavaField(it.newFieldName, it.type, it.isSkipInConstructor)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// COMMON_COROUTINES_TEST
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// CHECK_STATE_MACHINE
|
||||
|
||||
// FILE: inline.kt
|
||||
|
||||
class MyDeferred<T>(val t: suspend () -> T) {
|
||||
suspend fun await() = t()
|
||||
}
|
||||
|
||||
fun <T> async(block: suspend () -> T) = MyDeferred(block)
|
||||
|
||||
inline fun <T, R> map(source: MyDeferred<T>, crossinline mapper: (T) -> R) =
|
||||
async {
|
||||
mapper(source.await())
|
||||
}
|
||||
|
||||
inline fun <T, R1, R2> map2(source: MyDeferred<T>, crossinline mapper1: (T) -> R1, crossinline mapper2: (R1) -> R2) =
|
||||
async {
|
||||
val c = suspend {
|
||||
mapper1(source.await())
|
||||
}
|
||||
mapper2(c())
|
||||
}
|
||||
|
||||
inline fun <T, R1, R2, R3> map3(source: MyDeferred<T>, 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"
|
||||
}
|
||||
+61
@@ -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"
|
||||
}
|
||||
+69
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
+36
@@ -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"
|
||||
}
|
||||
+50
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+50
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+25
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+50
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user