Put suspend lambda's parameters to LVT

#KT-26412 Fixed
 #KT-28534 Fixed
This commit is contained in:
Ilmir Usmanov
2019-03-28 19:57:56 +03:00
parent 21fe5ac415
commit 6f14dcfacb
13 changed files with 139 additions and 94 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@@ -460,7 +460,6 @@ public class FunctionCodegen {
new Label(),
contextKind,
state,
Collections.emptyList(),
0);
mv.visitEnd();
@@ -675,28 +674,9 @@ public class FunctionCodegen {
);
}
List<ValueParameterDescriptor> destructuredParametersForSuspendLambda = new ArrayList<>();
if (context.getParentContext() instanceof ClosureContext) {
if (context instanceof InlineLambdaContext) {
CallableMemberDescriptor lambdaDescriptor = context.getContextDescriptor();
if (lambdaDescriptor instanceof FunctionDescriptor &&
((FunctionDescriptor) lambdaDescriptor).isSuspend()) {
destructuredParametersForSuspendLambda.addAll(lambdaDescriptor.getValueParameters());
}
} else {
FunctionDescriptor lambdaDescriptor = ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor();
if (lambdaDescriptor != null &&
CoroutineCodegenUtilKt.isResumeImplMethodName(
parentCodegen.state.getLanguageVersionSettings(), functionDescriptor.getName().asString()
)) {
destructuredParametersForSuspendLambda.addAll(lambdaDescriptor.getValueParameters());
}
}
}
generateLocalVariableTable(
mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind(), parentCodegen.state,
destructuredParametersForSuspendLambda, (functionFakeIndex >= 0 ? 1 : 0) + (lambdaFakeIndex >= 0 ? 1 : 0)
(functionFakeIndex >= 0 ? 1 : 0) + (lambdaFakeIndex >= 0 ? 1 : 0)
);
//TODO: it's best to move all below logic to 'generateLocalVariableTable' method
@@ -757,7 +737,6 @@ public class FunctionCodegen {
@NotNull Label methodEnd,
@NotNull OwnerKind ownerKind,
@NotNull GenerationState state,
@NotNull List<ValueParameterDescriptor> destructuredParametersForSuspendLambda,
int shiftForDestructuringVariables
) {
if (functionDescriptor.isSuspend() && !(functionDescriptor instanceof AnonymousFunctionDescriptor)) {
@@ -776,8 +755,7 @@ public class FunctionCodegen {
)
),
unwrapped,
thisType, methodBegin, methodEnd, ownerKind, state, destructuredParametersForSuspendLambda,
shiftForDestructuringVariables
thisType, methodBegin, methodEnd, ownerKind, state, shiftForDestructuringVariables
);
return;
}
@@ -786,7 +764,6 @@ public class FunctionCodegen {
generateLocalVariablesForParameters(mv,
jvmMethodSignature, functionDescriptor,
thisType, methodBegin, methodEnd, functionDescriptor.getValueParameters(),
destructuredParametersForSuspendLambda,
AsmUtil.isStaticMethod(ownerKind, functionDescriptor), state, shiftForDestructuringVariables
);
}
@@ -804,7 +781,7 @@ public class FunctionCodegen {
) {
generateLocalVariablesForParameters(
mv, jvmMethodSignature, functionDescriptor,
thisType, methodBegin, methodEnd, valueParameters, Collections.emptyList(), isStatic, state,
thisType, methodBegin, methodEnd, valueParameters, isStatic, state,
0);
}
@@ -816,7 +793,6 @@ public class FunctionCodegen {
@NotNull Label methodBegin,
@NotNull Label methodEnd,
Collection<ValueParameterDescriptor> valueParameters,
@NotNull List<ValueParameterDescriptor> destructuredParametersForSuspendLambda,
boolean isStatic,
@NotNull GenerationState state,
int shiftForDestructuringVariables
@@ -868,9 +844,7 @@ public class FunctionCodegen {
}
shift += shiftForDestructuringVariables;
shift = generateDestructuredParameterEntries(mv, methodBegin, methodEnd, valueParameters, typeMapper, shift);
shift = generateDestructuredParametersForSuspendLambda(mv, methodBegin, methodEnd, typeMapper, shift, destructuredParametersForSuspendLambda);
generateDestructuredParameterEntries(mv, methodBegin, methodEnd, destructuredParametersForSuspendLambda, typeMapper, shift);
generateDestructuredParameterEntries(mv, methodBegin, methodEnd, valueParameters, typeMapper, shift);
}
private static int generateDestructuredParameterEntries(
@@ -894,25 +868,6 @@ public class FunctionCodegen {
return shift;
}
private static int generateDestructuredParametersForSuspendLambda(
@NotNull MethodVisitor mv,
@NotNull Label methodBegin,
@NotNull Label methodEnd,
KotlinTypeMapper typeMapper,
int shift,
List<ValueParameterDescriptor> destructuredParametersForSuspendLambda
) {
for (ValueParameterDescriptor parameter : destructuredParametersForSuspendLambda) {
String nameForDestructuredParameter = VariableAsmNameManglingUtils.getNameForDestructuredParameterOrNull(parameter);
if (nameForDestructuredParameter == null) continue;
Type type = typeMapper.mapType(parameter.getType());
mv.visitLocalVariable(nameForDestructuredParameter, type.getDescriptor(), null, methodBegin, methodEnd, shift);
shift += type.getSize();
}
return shift;
}
private static String computeParameterName(int i, ValueParameterDescriptor parameter) {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(parameter);
if (element instanceof KtParameter && UnderscoreUtilKt.isSingleUnderscore((KtParameter) element)) {
@@ -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.
*/
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
import org.jetbrains.kotlin.codegen.inline.ReificationArgument
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
@@ -315,15 +314,16 @@ fun MemberDescriptor.isToArrayFromCollection(): Boolean {
fun FqName.topLevelClassInternalName() = JvmClassName.byClassId(ClassId(parent(), shortName())).internalName
fun FqName.topLevelClassAsmType(): Type = Type.getObjectType(topLevelClassInternalName())
fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodegen, valueParameters: List<ValueParameterDescriptor>) {
fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodegen, valueParameters: List<ValueParameterDescriptor>, endLabel: Label? = null) {
// Do not write line numbers until destructuring happens
// (otherwise destructuring variables will be uninitialized in the beginning of lambda)
codegen.runWithShouldMarkLineNumbers(false) {
for (parameterDescriptor in valueParameters) {
if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue
for (entry in parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()) {
codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type))
val variables = parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()
val indices = variables.map {
codegen.myFrameMap.enter(it, codegen.typeMapper.mapType(it.type))
}
val destructuringDeclaration =
@@ -335,6 +335,21 @@ fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodege
TransientReceiver(parameterDescriptor.type),
codegen.findLocalOrCapturedValue(parameterDescriptor) ?: error("Local var not found for parameter $parameterDescriptor")
)
if (endLabel != null) {
val label = Label()
codegen.v.mark(label)
for ((index, entry) in indices.zip(variables)) {
codegen.v.visitLocalVariable(
entry.name.asString(),
codegen.typeMapper.mapType(entry.type).descriptor,
null,
label,
endLabel,
index
)
}
}
}
}
}
@@ -38,11 +38,13 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode
abstract class AbstractCoroutineCodegen(
outerExpressionCodegen: ExpressionCodegen,
@@ -176,6 +178,8 @@ class CoroutineCodegenForLambda private constructor(
if (generateErasedCreate) getErasedCreateFunction() else getCreateFunction()
}
private val endLabel = Label()
private fun getCreateFunction(): SimpleFunctionDescriptor = SimpleFunctionDescriptorImpl.create(
funDescriptor.containingDeclaration,
Annotations.EMPTY,
@@ -425,12 +429,19 @@ class CoroutineCodegenForLambda private constructor(
val newIndex = myFrameMap.enter(parameter, mappedType)
v.store(newIndex, mappedType)
val name =
if (parameter is ReceiverParameterDescriptor) AsmUtil.RECEIVER_PARAMETER_NAME
else (getNameForDestructuredParameterOrNull(parameter as ValueParameterDescriptor) ?: parameter.name.asString())
val label = Label()
v.mark(label)
v.visitLocalVariable(name, mappedType.descriptor, null, label, endLabel, newIndex)
}
initializeVariablesForDestructuredLambdaParameters(this, originalSuspendFunctionDescriptor.valueParameters)
initializeVariablesForDestructuredLambdaParameters(this, originalSuspendFunctionDescriptor.valueParameters, endLabel)
}
private fun allFunctionParameters() =
private fun allFunctionParameters(): List<ParameterDescriptor> =
originalSuspendFunctionDescriptor.extensionReceiverParameter.let(::listOfNotNull) +
originalSuspendFunctionDescriptor.valueParameters
@@ -452,9 +463,10 @@ class CoroutineCodegenForLambda private constructor(
object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) {
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
if (forInline) return super.wrapMethodVisitor(mv, access, name, desc)
val addEndLabelMethodVisitor = AddEndLabelMethodVisitor(mv, access, name, desc, endLabel)
if (forInline) return super.wrapMethodVisitor(addEndLabelMethodVisitor, access, name, desc)
return CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null,
addEndLabelMethodVisitor, access, name, desc, null, null,
obtainClassBuilderForCoroutineState = { v },
element = element,
diagnostics = state.diagnostics,
@@ -502,6 +514,22 @@ class CoroutineCodegenForLambda private constructor(
}
}
private class AddEndLabelMethodVisitor(
delegate: MethodVisitor,
access: Int,
name: String,
desc: String,
private val endLabel: Label
): TransformationMethodVisitor(delegate, access, name, desc, null, null) {
override fun performTransformations(methodNode: MethodNode) {
methodNode.instructions.add(
withInstructionAdapter {
mark(endLabel)
}
)
}
}
class CoroutineCodegenForNamedFunction private constructor(
outerExpressionCodegen: ExpressionCodegen,
element: KtElement,