Cleanup inline codegen classes
Fix warnings, typos, formatting, break long lines, remove unused, add nullability annotations, inline small methods used only once
This commit is contained in:
+101
-102
@@ -23,8 +23,6 @@ import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder;
|
||||
import org.jetbrains.kotlin.codegen.FieldInfo;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
@@ -36,27 +34,16 @@ import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.isThis0;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
|
||||
public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjectTransformationInfo> {
|
||||
|
||||
protected final GenerationState state;
|
||||
|
||||
protected final KotlinTypeMapper typeMapper;
|
||||
private final InliningContext inliningContext;
|
||||
private final Type oldObjectType;
|
||||
private final boolean isSameModule;
|
||||
private final Map<String, List<String>> fieldNames = new HashMap<String, List<String>>();
|
||||
|
||||
private MethodNode constructor;
|
||||
|
||||
private String sourceInfo;
|
||||
|
||||
private String debugInfo;
|
||||
|
||||
private SourceMapper sourceMapper;
|
||||
|
||||
private final InliningContext inliningContext;
|
||||
|
||||
private final Type oldObjectType;
|
||||
|
||||
private final boolean isSameModule;
|
||||
|
||||
private final Map<String, List<String>> fieldNames = new HashMap<String, List<String>>();
|
||||
|
||||
public AnonymousObjectTransformer(
|
||||
@NotNull AnonymousObjectTransformationInfo transformationInfo,
|
||||
@NotNull InliningContext inliningContext,
|
||||
@@ -64,8 +51,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
) {
|
||||
super(transformationInfo, inliningContext.state);
|
||||
this.isSameModule = isSameModule;
|
||||
this.state = inliningContext.state;
|
||||
this.typeMapper = state.getTypeMapper();
|
||||
this.inliningContext = inliningContext;
|
||||
this.oldObjectType = Type.getObjectType(transformationInfo.getOldClassName());
|
||||
}
|
||||
@@ -94,25 +79,25 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions
|
||||
) {
|
||||
MethodNode node = new MethodNode(access, name, desc, signature, exceptions);
|
||||
if (name.equals("<init>")){
|
||||
if (constructor != null)
|
||||
if (name.equals("<init>")) {
|
||||
if (constructor != null) {
|
||||
throw new RuntimeException("Lambda, SAM or anonymous object should have only one constructor");
|
||||
|
||||
}
|
||||
constructor = node;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
methodsToTransform.add(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(
|
||||
int access, @NotNull String name, @NotNull String desc, String signature, Object value
|
||||
) {
|
||||
public FieldVisitor visitField(int access, @NotNull String name, @NotNull String desc, String signature, Object value) {
|
||||
addUniqueField(name);
|
||||
if (InlineCodegenUtil.isCapturedFieldName(name)) {
|
||||
return null;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, name, desc, signature, value);
|
||||
}
|
||||
}
|
||||
@@ -125,7 +110,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
|
||||
}
|
||||
}, ClassReader.SKIP_FRAMES);
|
||||
|
||||
@@ -218,29 +202,30 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
@NotNull ParametersBuilder capturedBuilder,
|
||||
boolean isConstructor
|
||||
) {
|
||||
ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode);
|
||||
Parameters parameters = isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode);
|
||||
ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifiedTypeInliner.reifyInstructions(sourceNode);
|
||||
Parameters parameters =
|
||||
isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode);
|
||||
|
||||
RegeneratedLambdaFieldRemapper remapper =
|
||||
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), transformationInfo.getNewClassName(),
|
||||
parameters, transformationInfo.getCapturedLambdasToInline(),
|
||||
parentRemapper, isConstructor);
|
||||
RegeneratedLambdaFieldRemapper remapper = new RegeneratedLambdaFieldRemapper(
|
||||
oldObjectType.getInternalName(), transformationInfo.getNewClassName(), parameters,
|
||||
transformationInfo.getCapturedLambdasToInline(), parentRemapper, isConstructor
|
||||
);
|
||||
|
||||
MethodInliner inliner =
|
||||
new MethodInliner(
|
||||
sourceNode,
|
||||
parameters,
|
||||
inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
|
||||
remapper,
|
||||
isSameModule,
|
||||
"Transformer for " + transformationInfo.getOldClassName(),
|
||||
sourceMapper,
|
||||
new InlineCallSiteInfo(
|
||||
transformationInfo.getOldClassName(),
|
||||
sourceNode.name,
|
||||
isConstructor ? transformationInfo.getNewConstructorDescriptor() : sourceNode.desc),
|
||||
null
|
||||
);
|
||||
MethodInliner inliner = new MethodInliner(
|
||||
sourceNode,
|
||||
parameters,
|
||||
inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
|
||||
remapper,
|
||||
isSameModule,
|
||||
"Transformer for " + transformationInfo.getOldClassName(),
|
||||
sourceMapper,
|
||||
new InlineCallSiteInfo(
|
||||
transformationInfo.getOldClassName(),
|
||||
sourceNode.name,
|
||||
isConstructor ? transformationInfo.getNewConstructorDescriptor() : sourceNode.desc
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
InlineResult result = inliner.doInline(deferringVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE);
|
||||
result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify);
|
||||
@@ -258,13 +243,13 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
List<Type> descTypes = new ArrayList<Type>();
|
||||
|
||||
Parameters constructorParams = constructorInlineBuilder.buildParameters();
|
||||
int [] capturedIndexes = new int [constructorParams.getReal().size() + constructorParams.getCaptured().size()];
|
||||
int[] capturedIndexes = new int[constructorParams.getReal().size() + constructorParams.getCaptured().size()];
|
||||
int index = 0;
|
||||
int size = 0;
|
||||
|
||||
//complex processing cause it could have super constructor call params
|
||||
for (ParameterInfo info : constructorParams) {
|
||||
if (!info.isSkipped()) { //not inlined
|
||||
if (!info.isSkipped) { //not inlined
|
||||
if (info.isCaptured() || info instanceof CapturedParamInfo) {
|
||||
capturedIndexes[index] = size;
|
||||
index++;
|
||||
@@ -280,17 +265,16 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()]));
|
||||
//TODO for inline method make public class
|
||||
transformationInfo.setNewConstructorDescriptor(constructorDescriptor);
|
||||
MethodVisitor constructorVisitor = classBuilder.newMethod(NO_ORIGIN,
|
||||
AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
|
||||
"<init>", constructorDescriptor,
|
||||
null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
MethodVisitor constructorVisitor = classBuilder.newMethod(
|
||||
NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||
);
|
||||
|
||||
final Label newBodyStartLabel = new Label();
|
||||
constructorVisitor.visitLabel(newBodyStartLabel);
|
||||
//initialize captured fields
|
||||
List<NewJavaField> newFieldsWithSkipped = TransformationUtilsKt.getNewFieldsToGenerate(allCapturedBuilder.listCaptured());
|
||||
List<FieldInfo> fieldInfoWithSkipped = TransformationUtilsKt.transformToFieldInfo(
|
||||
Type.getObjectType(transformationInfo.getNewClassName()), newFieldsWithSkipped);
|
||||
List<FieldInfo> fieldInfoWithSkipped =
|
||||
TransformationUtilsKt.transformToFieldInfo(Type.getObjectType(transformationInfo.getNewClassName()), newFieldsWithSkipped);
|
||||
|
||||
int paramIndex = 0;
|
||||
InstructionAdapter capturedFieldInitializer = new InstructionAdapter(constructorVisitor);
|
||||
@@ -311,23 +295,28 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
|
||||
if (fake.getLambda() != null) {
|
||||
//set remap value to skip this fake (captured with lambda already skipped)
|
||||
StackValue composed = StackValue.field(fake.getType(),
|
||||
oldObjectType,
|
||||
fake.getNewFieldName(),
|
||||
false,
|
||||
StackValue.LOCAL_0);
|
||||
StackValue composed = StackValue.field(
|
||||
fake.getType(),
|
||||
oldObjectType,
|
||||
fake.getNewFieldName(),
|
||||
false,
|
||||
StackValue.LOCAL_0
|
||||
);
|
||||
fake.setRemapValue(composed);
|
||||
}
|
||||
}
|
||||
|
||||
MethodNode intermediateMethodNode = new MethodNode(AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
MethodNode intermediateMethodNode =
|
||||
new MethodNode(AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true);
|
||||
|
||||
AbstractInsnNode first = intermediateMethodNode.instructions.getFirst();
|
||||
final Label oldStartLabel = first instanceof LabelNode ? ((LabelNode) first).getLabel() : null;
|
||||
intermediateMethodNode.accept(new MethodBodyVisitor(capturedFieldInitializer) {
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
|
||||
public void visitLocalVariable(
|
||||
@NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index
|
||||
) {
|
||||
if (oldStartLabel == start) {
|
||||
start = newBodyStartLabel;//patch for jack&jill
|
||||
}
|
||||
@@ -335,14 +324,13 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
}
|
||||
});
|
||||
constructorVisitor.visitEnd();
|
||||
AsmUtil.genClosureFields(TransformationUtilsKt.toNameTypePair(TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder);
|
||||
AsmUtil.genClosureFields(
|
||||
TransformationUtilsKt.toNameTypePair(TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Parameters getMethodParametersWithCaptured(
|
||||
@NotNull ParametersBuilder capturedBuilder,
|
||||
@NotNull MethodNode sourceNode
|
||||
) {
|
||||
private Parameters getMethodParametersWithCaptured(@NotNull ParametersBuilder capturedBuilder, @NotNull MethodNode sourceNode) {
|
||||
ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(oldObjectType, sourceNode.desc);
|
||||
for (CapturedParamInfo param : capturedBuilder.listCaptured()) {
|
||||
builder.addCapturedParamCopy(param);
|
||||
@@ -353,26 +341,23 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
@NotNull
|
||||
private static DeferredMethodVisitor newMethod(@NotNull final ClassBuilder builder, @NotNull final MethodNode original) {
|
||||
return new DeferredMethodVisitor(
|
||||
new MethodNode(original.access,
|
||||
original.name,
|
||||
original.desc,
|
||||
original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)),
|
||||
|
||||
new MethodNode(
|
||||
original.access, original.name, original.desc, original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
),
|
||||
new Function0<MethodVisitor>() {
|
||||
@Override
|
||||
public MethodVisitor invoke() {
|
||||
return builder.newMethod(
|
||||
NO_ORIGIN,
|
||||
original.access,
|
||||
original.name,
|
||||
original.desc,
|
||||
original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions));
|
||||
NO_ORIGIN, original.access, original.name, original.desc, original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<CapturedParamInfo> extractParametersMappingAndPatchConstructor(
|
||||
@NotNull MethodNode constructor,
|
||||
@NotNull ParametersBuilder capturedParamBuilder,
|
||||
@@ -380,8 +365,8 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
@NotNull final AnonymousObjectTransformationInfo transformationInfo,
|
||||
@NotNull FieldRemapper parentFieldRemapper
|
||||
) {
|
||||
|
||||
CapturedParamOwner owner = new CapturedParamOwner() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.getObjectType(transformationInfo.getOldClassName());
|
||||
@@ -400,7 +385,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
FieldInsnNode fieldNode = (FieldInsnNode) cur;
|
||||
String fieldName = fieldNode.name;
|
||||
if (fieldNode.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldName)) {
|
||||
|
||||
boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
|
||||
boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;
|
||||
|
||||
@@ -410,8 +394,13 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
|
||||
int varIndex = previous.var;
|
||||
LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
|
||||
String newFieldName = isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values()) ? getNewFieldName(fieldName, true) : fieldName;
|
||||
CapturedParamInfo info = capturedParamBuilder.addCapturedParam(owner, fieldName, newFieldName, Type.getType(fieldNode.desc), lambdaInfo != null, null);
|
||||
String newFieldName =
|
||||
isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values())
|
||||
? getNewFieldName(fieldName, true)
|
||||
: fieldName;
|
||||
CapturedParamInfo info = capturedParamBuilder.addCapturedParam(
|
||||
owner, fieldName, newFieldName, Type.getType(fieldNode.desc), lambdaInfo != null, null
|
||||
);
|
||||
if (lambdaInfo != null) {
|
||||
info.setLambda(lambdaInfo);
|
||||
capturedLambdas.add(lambdaInfo);
|
||||
@@ -440,14 +429,15 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE);
|
||||
}
|
||||
|
||||
Type [] types = Type.getArgumentTypes(constructorDesc);
|
||||
Type[] types = Type.getArgumentTypes(constructorDesc);
|
||||
for (Type type : types) {
|
||||
LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex());
|
||||
ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null, null);
|
||||
ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null);
|
||||
parameterInfo.setLambda(info);
|
||||
if (capturedParams.contains(parameterInfo.getIndex())) {
|
||||
parameterInfo.setCaptured(true);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//otherwise it's super constructor parameter
|
||||
}
|
||||
}
|
||||
@@ -456,7 +446,9 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
//TODO: some of such parameters could be skipped - we should perform additional analysis
|
||||
Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>(); //captured var of inlined parameter
|
||||
List<CapturedParamDesc> allRecapturedParameters = new ArrayList<CapturedParamDesc>();
|
||||
boolean addCapturedNotAddOuter = parentFieldRemapper.isRoot() || (parentFieldRemapper instanceof InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot());
|
||||
boolean addCapturedNotAddOuter =
|
||||
parentFieldRemapper.isRoot() ||
|
||||
(parentFieldRemapper instanceof InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot());
|
||||
Map<String, CapturedParamInfo> alreadyAdded = new HashMap<String, CapturedParamInfo>();
|
||||
for (LambdaInfo info : capturedLambdas) {
|
||||
if (addCapturedNotAddOuter) {
|
||||
@@ -466,16 +458,20 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
|
||||
CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(
|
||||
desc,
|
||||
alreadyAddedParam != null ? alreadyAddedParam.getNewFieldName() : getNewFieldName(desc.getFieldName(), false));
|
||||
StackValue composed = StackValue.field(desc.getType(),
|
||||
oldObjectType, /*TODO owner type*/
|
||||
recapturedParamInfo.getNewFieldName(),
|
||||
false,
|
||||
StackValue.LOCAL_0);
|
||||
alreadyAddedParam != null ? alreadyAddedParam.getNewFieldName() : getNewFieldName(desc.getFieldName(), false)
|
||||
);
|
||||
StackValue composed = StackValue.field(
|
||||
desc.getType(),
|
||||
oldObjectType, /*TODO owner type*/
|
||||
recapturedParamInfo.getNewFieldName(),
|
||||
false,
|
||||
StackValue.LOCAL_0
|
||||
);
|
||||
recapturedParamInfo.setRemapValue(composed);
|
||||
allRecapturedParameters.add(desc);
|
||||
|
||||
constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()).setRemapValue(composed);
|
||||
constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName())
|
||||
.setRemapValue(composed);
|
||||
if (alreadyAddedParam != null) {
|
||||
recapturedParamInfo.setSkipInConstructor(true);
|
||||
}
|
||||
@@ -495,12 +491,14 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
final Type ownerType = Type.getObjectType(parent.getLambdaInternalName());
|
||||
|
||||
CapturedParamDesc desc = new CapturedParamDesc(new CapturedParamOwner() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Type getType() {
|
||||
return ownerType;
|
||||
}
|
||||
}, InlineCodegenUtil.THIS, ownerType);
|
||||
CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, InlineCodegenUtil.THIS$0/*outer lambda/object*/);
|
||||
CapturedParamInfo recapturedParamInfo =
|
||||
capturedParamBuilder.addCapturedParam(desc, InlineCodegenUtil.THIS$0/*outer lambda/object*/);
|
||||
StackValue composed = StackValue.LOCAL_0;
|
||||
recapturedParamInfo.setRemapValue(composed);
|
||||
allRecapturedParameters.add(desc);
|
||||
@@ -514,7 +512,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
return constructorAdditionalFakeParams;
|
||||
}
|
||||
|
||||
private static boolean shouldRenameThis0(@NotNull FieldRemapper parentFieldRemapper, Collection<LambdaInfo> values) {
|
||||
private static boolean shouldRenameThis0(@NotNull FieldRemapper parentFieldRemapper, @NotNull Collection<LambdaInfo> values) {
|
||||
if (isFirstDeclSiteLambdaFieldRemapper(parentFieldRemapper)) {
|
||||
for (LambdaInfo value : values) {
|
||||
for (CapturedParamDesc desc : value.getCapturedVars()) {
|
||||
@@ -528,11 +526,12 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNewFieldName(@NotNull String oldName, boolean originalField) {
|
||||
private String getNewFieldName(@NotNull String oldName, boolean originalField) {
|
||||
if (InlineCodegenUtil.THIS$0.equals(oldName)) {
|
||||
if (!originalField) {
|
||||
return oldName;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//rename original 'this$0' in declaration site lambda (inside inline function) to use this$0 only for outer lambda/object access on call site
|
||||
return addUniqueField(oldName + InlineCodegenUtil.INLINE_FUN_THIS_0_SUFFIX);
|
||||
}
|
||||
@@ -553,7 +552,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
return newName;
|
||||
}
|
||||
|
||||
private static boolean isFirstDeclSiteLambdaFieldRemapper(FieldRemapper parentRemapper) {
|
||||
private static boolean isFirstDeclSiteLambdaFieldRemapper(@NotNull FieldRemapper parentRemapper) {
|
||||
return !(parentRemapper instanceof RegeneratedLambdaFieldRemapper) && !(parentRemapper instanceof InlinedLambdaRemapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
|
||||
|
||||
class AsmTypeRemapper(val typeRemapper: TypeRemapper, val isDefaultGeneration: Boolean, val result: InlineResult) : Remapper() {
|
||||
|
||||
override fun map(type: String): String {
|
||||
return typeRemapper.map(type)
|
||||
}
|
||||
@@ -33,7 +32,6 @@ class AsmTypeRemapper(val typeRemapper: TypeRemapper, val isDefaultGeneration: B
|
||||
}
|
||||
|
||||
return object : RemappingSignatureAdapter(v, this) {
|
||||
|
||||
override fun visitTypeVariable(name: String) {
|
||||
/*TODO try to erase absent type variable*/
|
||||
val mapping = typeRemapper.mapTypeParameter(name) ?: return super.visitTypeVariable(name)
|
||||
@@ -54,4 +52,4 @@ class AsmTypeRemapper(val typeRemapper: TypeRemapper, val isDefaultGeneration: B
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,4 @@ public class CapturedParamDesc {
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CapturedParamDesc createDesc(@NotNull CapturedParamOwner containingLambdaInfo, @NotNull String fieldName, @NotNull Type type) {
|
||||
return new CapturedParamDesc(containingLambdaInfo, fieldName, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,35 +17,24 @@
|
||||
package org.jetbrains.kotlin.codegen.inline;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public class CapturedParamInfo extends ParameterInfo {
|
||||
|
||||
public static final CapturedParamInfo STUB = new CapturedParamInfo(CapturedParamDesc.createDesc(new CapturedParamOwner() {
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.getObjectType("STUB");
|
||||
}
|
||||
}, "STUB", Type.getObjectType("STUB")), true, -1, -1);
|
||||
|
||||
public final CapturedParamDesc desc;
|
||||
|
||||
private final String newFieldName;
|
||||
|
||||
private boolean skipInConstructor;
|
||||
|
||||
public CapturedParamInfo(@NotNull CapturedParamDesc desc, boolean skipped, int index, int remapIndex) {
|
||||
this(desc, desc.getFieldName(), skipped, index, remapIndex);
|
||||
}
|
||||
|
||||
public CapturedParamInfo(@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, int remapIndex) {
|
||||
super(desc.getType(), skipped, index, remapIndex, index);
|
||||
this.desc = desc;
|
||||
this.newFieldName = newFieldName;
|
||||
}
|
||||
|
||||
public CapturedParamInfo(@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, StackValue remapIndex) {
|
||||
public CapturedParamInfo(
|
||||
@NotNull CapturedParamDesc desc, @NotNull String newFieldName, boolean skipped, int index, @Nullable StackValue remapIndex
|
||||
) {
|
||||
super(desc.getType(), skipped, index, remapIndex, index);
|
||||
this.desc = desc;
|
||||
this.newFieldName = newFieldName;
|
||||
@@ -67,9 +56,9 @@ public class CapturedParamInfo extends ParameterInfo {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CapturedParamInfo clone(int newIndex, StackValue newRamapIndex) {
|
||||
CapturedParamInfo capturedParamInfo = new CapturedParamInfo(desc, newFieldName, isSkipped, newIndex, newRamapIndex);
|
||||
capturedParamInfo.setLambda(lambda);
|
||||
private CapturedParamInfo clone(int newIndex, @Nullable StackValue newRemapIndex) {
|
||||
CapturedParamInfo capturedParamInfo = new CapturedParamInfo(desc, newFieldName, isSkipped, newIndex, newRemapIndex);
|
||||
capturedParamInfo.setLambda(getLambda());
|
||||
capturedParamInfo.setSkipInConstructor(skipInConstructor);
|
||||
return capturedParamInfo;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public interface CapturedParamOwner {
|
||||
@NotNull
|
||||
Type getType();
|
||||
}
|
||||
|
||||
+19
-43
@@ -17,18 +17,12 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import com.google.common.collect.LinkedListMultimap
|
||||
import java.util.ArrayList
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.util.Comparator
|
||||
import java.util.Collections
|
||||
import java.util.*
|
||||
|
||||
abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
|
||||
|
||||
val tryBlocksMetaInfo: IntervalMetaInfo<TryCatchBlockNodeInfo> = IntervalMetaInfo()
|
||||
|
||||
val localVarsMetaInfo: IntervalMetaInfo<LocalVarNodeWrapper> = IntervalMetaInfo()
|
||||
|
||||
var nextFreeLocalIndex: Int = parameterSize
|
||||
@@ -70,11 +64,11 @@ abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
|
||||
result
|
||||
}
|
||||
|
||||
Collections.sort<TryCatchBlockNodeInfo>(intervals, comp)
|
||||
Collections.sort(intervals, comp)
|
||||
return intervals
|
||||
}
|
||||
|
||||
protected fun substituteTryBlockNodes(node: MethodNode) {
|
||||
fun substituteTryBlockNodes(node: MethodNode) {
|
||||
node.tryCatchBlocks.clear()
|
||||
sortTryCatchBlocks(tryBlocksMetaInfo.allIntervals)
|
||||
for (info in tryBlocksMetaInfo.getMeaningfulIntervals()) {
|
||||
@@ -82,7 +76,6 @@ abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun substituteLocalVarTable(node: MethodNode) {
|
||||
node.localVariables.clear()
|
||||
for (info in localVarsMetaInfo.getMeaningfulIntervals()) {
|
||||
@@ -92,13 +85,9 @@ abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
|
||||
}
|
||||
|
||||
class IntervalMetaInfo<T : SplittableInterval<T>> {
|
||||
|
||||
val intervalStarts = LinkedListMultimap.create<LabelNode, T>()
|
||||
|
||||
val intervalEnds = LinkedListMultimap.create<LabelNode, T>()
|
||||
|
||||
val allIntervals: ArrayList<T> = arrayListOf()
|
||||
|
||||
val currentIntervals: MutableSet<T> = linkedSetOf()
|
||||
|
||||
fun addNewInterval(newInfo: T) {
|
||||
@@ -117,17 +106,10 @@ class IntervalMetaInfo<T : SplittableInterval<T>> {
|
||||
intervalEnds.put(remapped.endLabel, remapped)
|
||||
}
|
||||
|
||||
fun splitCurrentIntervals(by : Interval, keepStart: Boolean): List<SplitPair<T>> {
|
||||
fun splitCurrentIntervals(by: Interval, keepStart: Boolean): List<SplitPair<T>> {
|
||||
return currentIntervals.map { split(it, by, keepStart) }
|
||||
}
|
||||
|
||||
fun splitAndRemoveIntervalsFromCurrents(by : Interval) {
|
||||
val copies = ArrayList(currentIntervals)
|
||||
copies.forEach {
|
||||
splitAndRemoveInterval(it, by, true)
|
||||
}
|
||||
}
|
||||
|
||||
fun processCurrent(curIns: LabelNode, directOrder: Boolean) {
|
||||
getInterval(curIns, directOrder).forEach {
|
||||
val added = currentIntervals.add(it)
|
||||
@@ -140,25 +122,27 @@ class IntervalMetaInfo<T : SplittableInterval<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
fun split(interval: T, by : Interval, keepStart: Boolean): SplitPair<T> {
|
||||
fun split(interval: T, by: Interval, keepStart: Boolean): SplitPair<T> {
|
||||
val split = interval.split(by, keepStart)
|
||||
if (!keepStart) {
|
||||
remapStartLabel(split.newPart.startLabel, split.patchedPart)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
remapEndLabel(split.newPart.endLabel, split.patchedPart)
|
||||
}
|
||||
addNewInterval(split.newPart)
|
||||
return split
|
||||
}
|
||||
|
||||
fun splitAndRemoveInterval(interval: T, by : Interval, keepStart: Boolean): SplitPair<T> {
|
||||
fun splitAndRemoveInterval(interval: T, by: Interval, keepStart: Boolean): SplitPair<T> {
|
||||
val splitPair = split(interval, by, keepStart)
|
||||
val removed = currentIntervals.remove(splitPair.patchedPart)
|
||||
assert(removed, {"Wrong interval structure: $splitPair"})
|
||||
assert(removed) { "Wrong interval structure: $splitPair" }
|
||||
return splitPair
|
||||
}
|
||||
|
||||
fun getInterval(curIns: LabelNode, isOpen: Boolean) = if (isOpen) intervalStarts.get(curIns) else intervalEnds.get(curIns)
|
||||
fun getInterval(curIns: LabelNode, isOpen: Boolean) =
|
||||
if (isOpen) intervalStarts.get(curIns) else intervalEnds.get(curIns)
|
||||
}
|
||||
|
||||
private fun Interval.isMeaningless(): Boolean {
|
||||
@@ -175,23 +159,16 @@ fun <T : SplittableInterval<T>> IntervalMetaInfo<T>.getMeaningfulIntervals(): Li
|
||||
}
|
||||
|
||||
class DefaultProcessor(val node: MethodNode, parameterSize: Int) : CoveringTryCatchNodeProcessor(parameterSize) {
|
||||
|
||||
init {
|
||||
node.tryCatchBlocks.forEach { addTryNode(it) }
|
||||
node.localVariables.forEach { addLocalVarNode(it) }
|
||||
node.tryCatchBlocks.forEach {
|
||||
tryBlocksMetaInfo.addNewInterval(TryCatchBlockNodeInfo(it, false))
|
||||
}
|
||||
node.localVariables.forEach {
|
||||
localVarsMetaInfo.addNewInterval(LocalVarNodeWrapper(it))
|
||||
}
|
||||
}
|
||||
|
||||
fun addLocalVarNode(it: LocalVariableNode) {
|
||||
localVarsMetaInfo.addNewInterval(LocalVarNodeWrapper(it))
|
||||
}
|
||||
|
||||
fun addTryNode(node: TryCatchBlockNode) {
|
||||
tryBlocksMetaInfo.addNewInterval(TryCatchBlockNodeInfo(node, false))
|
||||
}
|
||||
|
||||
override fun instructionIndex(inst: AbstractInsnNode): Int {
|
||||
return node.instructions.indexOf(inst)
|
||||
}
|
||||
override fun instructionIndex(inst: AbstractInsnNode): Int = node.instructions.indexOf(inst)
|
||||
}
|
||||
|
||||
class LocalVarNodeWrapper(val node: LocalVariableNode) : Interval, SplittableInterval<LocalVarNodeWrapper> {
|
||||
@@ -216,5 +193,4 @@ class LocalVarNodeWrapper(val node: LocalVariableNode) : Interval, SplittableInt
|
||||
LocalVariableNode(node.name, node.desc, node.signature, newPartInterval.first, newPartInterval.second, node.index)
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
@@ -29,30 +28,24 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class FieldRemapper {
|
||||
|
||||
private final String lambdaInternalName;
|
||||
|
||||
protected FieldRemapper parent;
|
||||
|
||||
private final String lambdaInternalName;
|
||||
private final Parameters params;
|
||||
|
||||
public FieldRemapper(@Nullable String lambdaInternalName, @Nullable FieldRemapper parent, @NotNull Parameters methodParams) {
|
||||
this.lambdaInternalName = lambdaInternalName;
|
||||
this.parent = parent;
|
||||
params = methodParams;
|
||||
this.params = methodParams;
|
||||
}
|
||||
|
||||
protected boolean canProcess(@NotNull String fieldOwner, String fieldName, boolean isFolding) {
|
||||
protected boolean canProcess(@NotNull String fieldOwner, @NotNull String fieldName, boolean isFolding) {
|
||||
return fieldOwner.equals(getLambdaInternalName()) &&
|
||||
//don't process general field of anonymous objects
|
||||
InlineCodegenUtil.isCapturedFieldName(fieldName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AbstractInsnNode foldFieldAccessChainIfNeeded(
|
||||
@NotNull List<AbstractInsnNode> capturedFieldAccess,
|
||||
@NotNull MethodNode node
|
||||
) {
|
||||
public AbstractInsnNode foldFieldAccessChainIfNeeded(@NotNull List<AbstractInsnNode> capturedFieldAccess, @NotNull MethodNode node) {
|
||||
if (capturedFieldAccess.size() == 1) {
|
||||
//just aload
|
||||
return null;
|
||||
@@ -72,33 +65,33 @@ public class FieldRemapper {
|
||||
int currentInstruction,
|
||||
@NotNull MethodNode node
|
||||
) {
|
||||
AbstractInsnNode transformed = null;
|
||||
boolean checkParent = !isRoot() && currentInstruction < capturedFieldAccess.size() - 1;
|
||||
if (checkParent) {
|
||||
transformed = parent.foldFieldAccessChainIfNeeded(capturedFieldAccess, currentInstruction + 1, node);
|
||||
}
|
||||
|
||||
if (transformed == null) {
|
||||
//if parent couldn't transform
|
||||
FieldInsnNode insnNode = (FieldInsnNode) capturedFieldAccess.get(currentInstruction);
|
||||
if (canProcess(insnNode.owner, insnNode.name, true)) {
|
||||
insnNode.name = "$$$" + insnNode.name;
|
||||
insnNode.setOpcode(Opcodes.GETSTATIC);
|
||||
|
||||
AbstractInsnNode next = capturedFieldAccess.get(0);
|
||||
while (next != insnNode) {
|
||||
AbstractInsnNode toDelete = next;
|
||||
next = next.getNext();
|
||||
node.instructions.remove(toDelete);
|
||||
}
|
||||
|
||||
transformed = capturedFieldAccess.get(capturedFieldAccess.size() - 1);
|
||||
AbstractInsnNode transformed = parent.foldFieldAccessChainIfNeeded(capturedFieldAccess, currentInstruction + 1, node);
|
||||
if (transformed != null) {
|
||||
return transformed;
|
||||
}
|
||||
}
|
||||
|
||||
return transformed;
|
||||
FieldInsnNode insnNode = (FieldInsnNode) capturedFieldAccess.get(currentInstruction);
|
||||
if (canProcess(insnNode.owner, insnNode.name, true)) {
|
||||
insnNode.name = "$$$" + insnNode.name;
|
||||
insnNode.setOpcode(Opcodes.GETSTATIC);
|
||||
|
||||
AbstractInsnNode next = capturedFieldAccess.get(0);
|
||||
while (next != insnNode) {
|
||||
AbstractInsnNode toDelete = next;
|
||||
next = next.getNext();
|
||||
node.instructions.remove(toDelete);
|
||||
}
|
||||
|
||||
return capturedFieldAccess.get(capturedFieldAccess.size() - 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode) {
|
||||
return findField(fieldInsnNode, params.getCaptured());
|
||||
}
|
||||
@@ -106,13 +99,15 @@ public class FieldRemapper {
|
||||
@Nullable
|
||||
protected CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection<CapturedParamInfo> captured) {
|
||||
for (CapturedParamInfo valueDescriptor : captured) {
|
||||
if (valueDescriptor.getOriginalFieldName().equals(fieldInsnNode.name) && fieldInsnNode.owner.equals(valueDescriptor.getContainingLambdaName())) {
|
||||
if (valueDescriptor.getOriginalFieldName().equals(fieldInsnNode.name) &&
|
||||
valueDescriptor.getContainingLambdaName().equals(fieldInsnNode.owner)) {
|
||||
return valueDescriptor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FieldRemapper getParent() {
|
||||
return parent;
|
||||
}
|
||||
@@ -131,8 +126,7 @@ public class FieldRemapper {
|
||||
|
||||
@Nullable
|
||||
public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) {
|
||||
CapturedParamInfo field = MethodInliner.findCapturedField(node, this);
|
||||
return field.getRemapValue();
|
||||
return MethodInliner.findCapturedField(node, this).getRemapValue();
|
||||
}
|
||||
|
||||
public boolean isInsideInliningLambda() {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.inline;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
@@ -27,19 +28,16 @@ import java.util.List;
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getLoadStoreArgSize;
|
||||
|
||||
public class InlineAdapter extends InstructionAdapter {
|
||||
|
||||
private int nextLocalIndex = 0;
|
||||
private final SourceMapper sourceMapper;
|
||||
|
||||
private boolean isLambdaInlining = false;
|
||||
|
||||
private final List<CatchBlock> blocks = new ArrayList<CatchBlock>();
|
||||
|
||||
private boolean isLambdaInlining = false;
|
||||
private int nextLocalIndex = 0;
|
||||
private int nextLocalIndexBeforeInline = -1;
|
||||
|
||||
public InlineAdapter(MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
|
||||
public InlineAdapter(@NotNull MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
|
||||
super(InlineCodegenUtil.API, mv);
|
||||
nextLocalIndex = localsSize;
|
||||
this.nextLocalIndex = localsSize;
|
||||
this.sourceMapper = sourceMapper;
|
||||
}
|
||||
|
||||
@@ -70,15 +68,15 @@ public class InlineAdapter extends InstructionAdapter {
|
||||
this.isLambdaInlining = isInlining;
|
||||
if (isInlining) {
|
||||
nextLocalIndexBeforeInline = nextLocalIndex;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
nextLocalIndex = nextLocalIndexBeforeInline;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start,
|
||||
Label end, Label handler, String type) {
|
||||
if(!isLambdaInlining) {
|
||||
public void visitTryCatchBlock(@NotNull Label start, @NotNull Label end, @NotNull Label handler, @Nullable String type) {
|
||||
if (!isLambdaInlining) {
|
||||
blocks.add(new CatchBlock(start, end, handler, type));
|
||||
}
|
||||
else {
|
||||
@@ -87,7 +85,7 @@ public class InlineAdapter extends InstructionAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
public void visitLineNumber(int line, @NotNull Label start) {
|
||||
if (InlineCodegenUtil.GENERATE_SMAP) {
|
||||
line = sourceMapper.mapLineNumber(line);
|
||||
}
|
||||
@@ -111,7 +109,7 @@ public class InlineAdapter extends InstructionAdapter {
|
||||
private final Label handler;
|
||||
private final String type;
|
||||
|
||||
public CatchBlock(Label start, Label end, Label handler, String type) {
|
||||
public CatchBlock(@NotNull Label start, @NotNull Label end, @NotNull Label handler, @Nullable String type) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.handler = handler;
|
||||
|
||||
@@ -34,7 +34,8 @@ inline fun <K, V> SLRUMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
||||
val answer = defaultValue()
|
||||
put(key, answer)
|
||||
answer
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
@@ -85,7 +84,9 @@ public class InlineCodegen extends CallGenerator {
|
||||
private final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
|
||||
|
||||
private final ReifiedTypeInliner reifiedTypeInliner;
|
||||
@Nullable private final TypeParameterMappings typeParameterMappings;
|
||||
|
||||
@Nullable
|
||||
private final TypeParameterMappings typeParameterMappings;
|
||||
|
||||
private LambdaInfo activeLambda;
|
||||
|
||||
@@ -131,35 +132,53 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void genCallInner(@NotNull Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) {
|
||||
SMAPAndMethodNode nodeAndSmap = null;
|
||||
public void genCallInner(
|
||||
@NotNull Callable callableMethod,
|
||||
@Nullable ResolvedCall<?> resolvedCall,
|
||||
boolean callDefault,
|
||||
@NotNull ExpressionCodegen codegen
|
||||
) {
|
||||
if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
|
||||
generateStub(resolvedCall, codegen);
|
||||
return;
|
||||
}
|
||||
|
||||
SMAPAndMethodNode nodeAndSmap = null;
|
||||
try {
|
||||
nodeAndSmap = createMethodNode(callDefault);
|
||||
nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault);
|
||||
endCall(inlineCall(nodeAndSmap));
|
||||
}
|
||||
catch (CompilationException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (InlineException e) {
|
||||
throw throwCompilationException(nodeAndSmap, e, false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
boolean generateNodeText = !(e instanceof InlineException);
|
||||
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor());
|
||||
throw new CompilationException("Couldn't inline method call '" +
|
||||
functionDescriptor.getName() +
|
||||
"' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
|
||||
(generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""),
|
||||
e, callElement);
|
||||
throw throwCompilationException(nodeAndSmap, e, true);
|
||||
}
|
||||
finally {
|
||||
state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
|
||||
}
|
||||
}
|
||||
|
||||
protected void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
|
||||
@NotNull
|
||||
private CompilationException throwCompilationException(
|
||||
@Nullable SMAPAndMethodNode nodeAndSmap, @NotNull Exception e, boolean generateNodeText
|
||||
) {
|
||||
CallableMemberDescriptor contextDescriptor = codegen.getContext().getContextDescriptor();
|
||||
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor);
|
||||
MethodNode node = nodeAndSmap != null ? nodeAndSmap.getNode() : null;
|
||||
throw new CompilationException(
|
||||
"Couldn't inline method call '" + functionDescriptor.getName() + "' into\n" +
|
||||
contextDescriptor + "\n" +
|
||||
(element != null ? element.getText() : "<no source>") +
|
||||
(generateNodeText ? ("\nCause: " + InlineCodegenUtil.getNodeText(node)) : ""),
|
||||
e, callElement
|
||||
);
|
||||
}
|
||||
|
||||
private void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
|
||||
leaveTemps();
|
||||
assert resolvedCall != null;
|
||||
String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
|
||||
@@ -176,25 +195,19 @@ public class InlineCodegen extends CallGenerator {
|
||||
codegen.markLineNumberAfterInlineIfNeeded();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private SMAPAndMethodNode createMethodNode(boolean callDefault) throws IOException {
|
||||
return createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, state);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static SMAPAndMethodNode createMethodNode(
|
||||
@NotNull final FunctionDescriptor functionDescriptor,
|
||||
@NotNull JvmMethodSignature jvmSignature,
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull CodegenContext context,
|
||||
boolean callDefault,
|
||||
@NotNull final GenerationState state
|
||||
boolean callDefault
|
||||
) {
|
||||
|
||||
KotlinTypeMapper typeMapper = state.getTypeMapper();
|
||||
final Method asmMethod = callDefault
|
||||
? typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind())
|
||||
: jvmSignature.getAsmMethod();
|
||||
final GenerationState state = codegen.getState();
|
||||
final Method asmMethod =
|
||||
callDefault
|
||||
? state.getTypeMapper().mapDefaultMethod(functionDescriptor, context.getContextKind())
|
||||
: jvmSignature.getAsmMethod();
|
||||
|
||||
MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod);
|
||||
|
||||
@@ -202,15 +215,18 @@ public class InlineCodegen extends CallGenerator {
|
||||
return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod);
|
||||
}
|
||||
|
||||
SMAPAndMethodNode resultInCache =
|
||||
InlineCacheKt
|
||||
.getOrPut(state.getInlineCache().getMethodNodeById(), methodId, new Function0<SMAPAndMethodNode>() {
|
||||
@Override
|
||||
public SMAPAndMethodNode invoke() {
|
||||
return doCreateMethodNodeFromCompiled(functionDescriptor,
|
||||
state, asmMethod);
|
||||
}
|
||||
});
|
||||
SMAPAndMethodNode resultInCache = InlineCacheKt.getOrPut(
|
||||
state.getInlineCache().getMethodNodeById(), methodId, new Function0<SMAPAndMethodNode>() {
|
||||
@Override
|
||||
public SMAPAndMethodNode invoke() {
|
||||
SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(functionDescriptor, state, asmMethod);
|
||||
if (result == null) {
|
||||
throw new IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.getNode()));
|
||||
}
|
||||
@@ -220,12 +236,13 @@ public class InlineCodegen extends CallGenerator {
|
||||
methodNode.instructions.resetLabels();
|
||||
MethodNode result = new MethodNode(
|
||||
API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature,
|
||||
methodNode.exceptions.toArray(ArrayUtil.EMPTY_STRING_ARRAY));
|
||||
ArrayUtil.toStringArray(methodNode.exceptions)
|
||||
);
|
||||
methodNode.accept(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
private static SMAPAndMethodNode doCreateMethodNodeFromCompiled(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull final GenerationState state,
|
||||
@@ -233,7 +250,6 @@ public class InlineCodegen extends CallGenerator {
|
||||
) {
|
||||
KotlinTypeMapper typeMapper = state.getTypeMapper();
|
||||
|
||||
SMAPAndMethodNode nodeAndSMAP;
|
||||
if (isBuiltInArrayIntrinsic(functionDescriptor)) {
|
||||
ClassId classId = IntrinsicArrayConstructorsKt.getClassId();
|
||||
byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, new Function0<byte[]>() {
|
||||
@@ -243,24 +259,13 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
});
|
||||
|
||||
nodeAndSMAP = InlineCodegenUtil.getMethodNode(
|
||||
bytes,
|
||||
asmMethod.getName(),
|
||||
asmMethod.getDescriptor(),
|
||||
classId
|
||||
);
|
||||
|
||||
if (nodeAndSMAP == null) {
|
||||
throw new IllegalStateException("Couldn't obtain array constructor body for " + descriptorName(functionDescriptor));
|
||||
}
|
||||
|
||||
return nodeAndSMAP;
|
||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId);
|
||||
}
|
||||
|
||||
assert functionDescriptor instanceof DeserializedSimpleFunctionDescriptor;
|
||||
assert functionDescriptor instanceof DeserializedSimpleFunctionDescriptor : "Not a deserialized function: " + functionDescriptor;
|
||||
|
||||
KotlinTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable(
|
||||
(DeserializedSimpleFunctionDescriptor) functionDescriptor);
|
||||
KotlinTypeMapper.ContainingClassesInfo containingClasses =
|
||||
typeMapper.getContainingClassesForDeserializedCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor);
|
||||
|
||||
final ClassId containerId = containingClasses.getImplClassId();
|
||||
|
||||
@@ -280,15 +285,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
});
|
||||
|
||||
nodeAndSMAP = InlineCodegenUtil.getMethodNode(
|
||||
bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId
|
||||
);
|
||||
|
||||
if (nodeAndSMAP == null) {
|
||||
throw new IllegalStateException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
|
||||
}
|
||||
|
||||
return nodeAndSMAP;
|
||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -304,27 +301,31 @@ public class InlineCodegen extends CallGenerator {
|
||||
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
|
||||
|
||||
if (!(element instanceof KtNamedFunction)) {
|
||||
throw new IllegalStateException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
|
||||
throw new IllegalStateException("Couldn't find declaration for function " + functionDescriptor);
|
||||
}
|
||||
KtNamedFunction inliningFunction = (KtNamedFunction) element;
|
||||
|
||||
MethodNode node = new MethodNode(InlineCodegenUtil.API,
|
||||
getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
|
||||
asmMethod.getName(),
|
||||
asmMethod.getDescriptor(),
|
||||
null,
|
||||
null);
|
||||
MethodNode node = new MethodNode(
|
||||
InlineCodegenUtil.API,
|
||||
getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
|
||||
asmMethod.getName(),
|
||||
asmMethod.getDescriptor(),
|
||||
null, null
|
||||
);
|
||||
|
||||
//for maxLocals calculation
|
||||
MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
|
||||
MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);
|
||||
CodegenContext parentContext = context.getParentContext();
|
||||
assert parentContext != null : "Context has no parent: " + context;
|
||||
MethodContext methodContext = parentContext.intoFunction(functionDescriptor);
|
||||
|
||||
SMAP smap;
|
||||
if (callDefault) {
|
||||
Type implementationOwner = state.getTypeMapper().mapImplementationOwner(functionDescriptor);
|
||||
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
|
||||
(FieldOwnerContext) methodContext.getParentContext(),
|
||||
implementationOwner.getInternalName());
|
||||
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(
|
||||
codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(),
|
||||
implementationOwner.getInternalName()
|
||||
);
|
||||
FunctionCodegen.generateDefaultImplBody(
|
||||
methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
|
||||
inliningFunction, parentCodegen, asmMethod
|
||||
@@ -332,7 +333,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
|
||||
}
|
||||
else {
|
||||
smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen, state);
|
||||
smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false, codegen);
|
||||
}
|
||||
maxCalcAdapter.visitMaxs(-1, -1);
|
||||
maxCalcAdapter.visitEnd();
|
||||
@@ -347,7 +348,8 @@ public class InlineCodegen extends CallGenerator {
|
||||
functionDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment;
|
||||
}
|
||||
|
||||
private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
|
||||
@NotNull
|
||||
private InlineResult inlineCall(@NotNull SMAPAndMethodNode nodeAndSmap) {
|
||||
DefaultSourceMapper defaultSourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
|
||||
defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber()));
|
||||
MethodNode node = nodeAndSmap.getNode();
|
||||
@@ -363,7 +365,8 @@ public class InlineCodegen extends CallGenerator {
|
||||
|
||||
InliningContext info = new RootInliningContext(
|
||||
expressionMap, state, codegen.getInlineNameGenerator().subGenerator(jvmSignature.getAsmMethod().getName()),
|
||||
codegen.getContext(), callElement, getInlineCallSiteInfo(), reifiedTypeInliner, typeParameterMappings);
|
||||
callElement, getInlineCallSiteInfo(), reifiedTypeInliner, typeParameterMappings
|
||||
);
|
||||
|
||||
MethodInliner inliner = new MethodInliner(
|
||||
node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
|
||||
@@ -374,7 +377,6 @@ public class InlineCodegen extends CallGenerator {
|
||||
|
||||
LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
|
||||
|
||||
|
||||
MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
|
||||
//hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
|
||||
adapter.visitInsn(Opcodes.NOP);
|
||||
@@ -392,7 +394,9 @@ public class InlineCodegen extends CallGenerator {
|
||||
};
|
||||
|
||||
List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
|
||||
generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index);
|
||||
generateAndInsertFinallyBlocks(
|
||||
adapter, infos, ((StackValue.Local) remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index
|
||||
);
|
||||
removeStaticInitializationTrigger(adapter);
|
||||
removeFinallyMarkers(adapter);
|
||||
|
||||
@@ -405,7 +409,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void removeStaticInitializationTrigger(MethodNode methodNode) {
|
||||
private static void removeStaticInitializationTrigger(@NotNull MethodNode methodNode) {
|
||||
InsnList insnList = methodNode.instructions;
|
||||
AbstractInsnNode insn = insnList.getFirst();
|
||||
while (insn != null) {
|
||||
@@ -420,6 +424,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private InlineCallSiteInfo getInlineCallSiteInfo() {
|
||||
MethodContext context = codegen.getContext();
|
||||
MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
|
||||
@@ -433,7 +438,9 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
JvmMethodSignature signature = typeMapper.mapSignatureSkipGeneric(context.getFunctionDescriptor(), context.getContextKind());
|
||||
return new InlineCallSiteInfo(parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor());
|
||||
return new InlineCallSiteInfo(
|
||||
parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor()
|
||||
);
|
||||
}
|
||||
|
||||
private void generateClosuresBodies() {
|
||||
@@ -442,25 +449,29 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
|
||||
@NotNull
|
||||
private SMAPAndMethodNode generateLambdaBody(@NotNull LambdaInfo info) {
|
||||
KtExpression declaration = info.getFunctionWithBodyOrCallableReference();
|
||||
FunctionDescriptor descriptor = info.getFunctionDescriptor();
|
||||
|
||||
MethodContext parentContext = codegen.getContext();
|
||||
|
||||
MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor, info.isCrossInline);
|
||||
MethodContext context =
|
||||
codegen.getContext().intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor, info.isCrossInline);
|
||||
|
||||
JvmMethodSignature jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(descriptor);
|
||||
Method asmMethod = jvmMethodSignature.getAsmMethod();
|
||||
MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), null, null);
|
||||
MethodNode methodNode = new MethodNode(
|
||||
InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()),
|
||||
asmMethod.getName(), asmMethod.getDescriptor(), null, null
|
||||
);
|
||||
|
||||
MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
|
||||
|
||||
SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true, codegen, state);
|
||||
SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true, codegen);
|
||||
adapter.visitMaxs(-1, -1);
|
||||
return new SMAPAndMethodNode(methodNode, smap);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static SMAP generateMethodBody(
|
||||
@NotNull MethodVisitor adapter,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@@ -468,32 +479,29 @@ public class InlineCodegen extends CallGenerator {
|
||||
@NotNull KtExpression expression,
|
||||
@NotNull JvmMethodSignature jvmMethodSignature,
|
||||
boolean isLambda,
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull GenerationState state
|
||||
|
||||
@NotNull ExpressionCodegen codegen
|
||||
) {
|
||||
FakeMemberCodegen parentCodegen =
|
||||
new FakeMemberCodegen(codegen.getParentCodegen(), expression,
|
||||
(FieldOwnerContext) context.getParentContext(),
|
||||
isLambda ? codegen.getParentCodegen().getClassName()
|
||||
: state.getTypeMapper().mapImplementationOwner(descriptor).getInternalName());
|
||||
GenerationState state = codegen.getState();
|
||||
|
||||
// Wrapping for preventing marking actual parent codegen as containing reified markers
|
||||
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(
|
||||
codegen.getParentCodegen(), expression, (FieldOwnerContext) context.getParentContext(),
|
||||
isLambda ? codegen.getParentCodegen().getClassName()
|
||||
: state.getTypeMapper().mapImplementationOwner(descriptor).getInternalName()
|
||||
);
|
||||
|
||||
FunctionGenerationStrategy strategy =
|
||||
expression instanceof KtCallableReferenceExpression ?
|
||||
new FunctionReferenceGenerationStrategy(
|
||||
state,
|
||||
descriptor,
|
||||
CallUtilKt.getResolvedCallWithAssert(((KtCallableReferenceExpression) expression).getCallableReference(),
|
||||
codegen.getBindingContext()
|
||||
)) :
|
||||
CallUtilKt.getResolvedCallWithAssert(
|
||||
((KtCallableReferenceExpression) expression).getCallableReference(), codegen.getBindingContext()
|
||||
)
|
||||
) :
|
||||
new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (KtDeclarationWithBody) expression);
|
||||
|
||||
FunctionCodegen.generateMethodBody(
|
||||
adapter, descriptor, context, jvmMethodSignature,
|
||||
strategy,
|
||||
// Wrapping for preventing marking actual parent codegen as containing reifier markers
|
||||
parentCodegen
|
||||
);
|
||||
FunctionCodegen.generateMethodBody(adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen);
|
||||
|
||||
if (isLambda) {
|
||||
codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.getReifiedTypeParametersUsages());
|
||||
@@ -514,13 +522,18 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
private static class FakeMemberCodegen extends MemberCodegen {
|
||||
private final MemberCodegen delegate;
|
||||
private final String className;
|
||||
|
||||
@NotNull final MemberCodegen delegate;
|
||||
@NotNull private final String className;
|
||||
|
||||
public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull KtElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public FakeMemberCodegen(
|
||||
@NotNull MemberCodegen wrapped,
|
||||
@NotNull KtElement declaration,
|
||||
@NotNull FieldOwnerContext codegenContext,
|
||||
@NotNull String className
|
||||
) {
|
||||
super(wrapped, declaration, codegenContext);
|
||||
delegate = wrapped;
|
||||
this.delegate = wrapped;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@@ -554,11 +567,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterParameterPut(
|
||||
@NotNull Type type,
|
||||
@Nullable StackValue stackValue,
|
||||
int parameterIndex
|
||||
) {
|
||||
public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, int parameterIndex) {
|
||||
putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
|
||||
}
|
||||
|
||||
@@ -588,11 +597,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
/*descriptor is null for captured vars*/
|
||||
public static boolean shouldPutValue(
|
||||
@NotNull Type type,
|
||||
@Nullable StackValue stackValue
|
||||
) {
|
||||
|
||||
private static boolean shouldPutValue(@NotNull Type type, @Nullable StackValue stackValue) {
|
||||
if (stackValue == null) {
|
||||
//default or vararg
|
||||
return true;
|
||||
@@ -626,7 +631,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void recordParameterValueInLocalVal(ParameterInfo... infos) {
|
||||
private void recordParameterValueInLocalVal(@NotNull ParameterInfo... infos) {
|
||||
int[] index = new int[infos.length];
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
ParameterInfo info = infos[i];
|
||||
@@ -650,34 +655,33 @@ public class InlineCodegen extends CallGenerator {
|
||||
@Override
|
||||
public void putHiddenParams() {
|
||||
if ((getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == 0) {
|
||||
invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
|
||||
invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false);
|
||||
}
|
||||
|
||||
for (JvmMethodParameterSignature param : jvmSignature.getValueParameters()) {
|
||||
if (param.getKind() == JvmMethodParameterKind.VALUE) {
|
||||
break;
|
||||
}
|
||||
invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
|
||||
invocationParamBuilder.addNextParameter(param.getAsmType(), false);
|
||||
}
|
||||
|
||||
invocationParamBuilder.markValueParametesStart();
|
||||
invocationParamBuilder.markValueParametersStart();
|
||||
List<ParameterInfo> hiddenParameters = invocationParamBuilder.buildParameters().getReal();
|
||||
recordParameterValueInLocalVal(hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()]));
|
||||
}
|
||||
|
||||
public void leaveTemps() {
|
||||
FrameMap frameMap = codegen.getFrameMap();
|
||||
private void leaveTemps() {
|
||||
List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
|
||||
for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
|
||||
ParameterInfo param = iterator.previous();
|
||||
if (!param.isSkippedOrRemapped()) {
|
||||
frameMap.leaveTemp(param.type);
|
||||
codegen.getFrameMap().leaveTemp(param.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*lambda or callable reference*/
|
||||
public boolean isInliningParameter(KtExpression expression, ValueParameterDescriptor valueParameterDescriptor) {
|
||||
private boolean isInliningParameter(@NotNull KtExpression expression, @NotNull ValueParameterDescriptor valueParameterDescriptor) {
|
||||
//TODO deparenthisise typed
|
||||
KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
|
||||
|
||||
@@ -691,17 +695,16 @@ public class InlineCodegen extends CallGenerator {
|
||||
isInlinableParameterExpression(deparenthesized);
|
||||
}
|
||||
|
||||
protected static boolean isInlinableParameterExpression(KtExpression deparenthesized) {
|
||||
private static boolean isInlinableParameterExpression(@Nullable KtExpression deparenthesized) {
|
||||
return deparenthesized instanceof KtLambdaExpression ||
|
||||
deparenthesized instanceof KtNamedFunction ||
|
||||
deparenthesized instanceof KtCallableReferenceExpression;
|
||||
}
|
||||
|
||||
public void rememberClosure(KtExpression expression, Type type, ValueParameterDescriptor parameter) {
|
||||
private void rememberClosure(@NotNull KtExpression expression, @NotNull Type type, @NotNull ValueParameterDescriptor parameter) {
|
||||
KtExpression lambda = KtPsiUtil.deparenthesize(expression);
|
||||
assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
|
||||
|
||||
|
||||
LambdaInfo info = new LambdaInfo(lambda, typeMapper, parameter.isCrossinline());
|
||||
|
||||
ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.getIndex());
|
||||
@@ -710,7 +713,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
|
||||
public static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
|
||||
if (lambdaOrFun != null) {
|
||||
@@ -737,18 +740,25 @@ public class InlineCodegen extends CallGenerator {
|
||||
activeLambda = null;
|
||||
}
|
||||
|
||||
public static CodegenContext getContext(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile) {
|
||||
@NotNull
|
||||
public static CodegenContext getContext(
|
||||
@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile
|
||||
) {
|
||||
if (descriptor instanceof PackageFragmentDescriptor) {
|
||||
return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile);
|
||||
}
|
||||
|
||||
CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state, sourceFile);
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
assert container != null : "No container for descriptor: " + descriptor;
|
||||
CodegenContext parent = getContext(container, state, sourceFile);
|
||||
|
||||
if (descriptor instanceof ScriptDescriptor) {
|
||||
List<ScriptDescriptor> earlierScripts = state.getReplSpecific().getEarlierScriptsForReplInterpreter();
|
||||
return parent.intoScript((ScriptDescriptor) descriptor,
|
||||
earlierScripts == null ? Collections.emptyList() : earlierScripts,
|
||||
(ClassDescriptor) descriptor, state.getTypeMapper());
|
||||
return parent.intoScript(
|
||||
(ScriptDescriptor) descriptor,
|
||||
earlierScripts == null ? Collections.emptyList() : earlierScripts,
|
||||
(ClassDescriptor) descriptor, state.getTypeMapper()
|
||||
);
|
||||
}
|
||||
else if (descriptor instanceof ClassDescriptor) {
|
||||
OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
|
||||
@@ -758,11 +768,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
return parent.intoFunction((FunctionDescriptor) descriptor);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
|
||||
}
|
||||
|
||||
private static String descriptorName(DeclarationDescriptor descriptor) {
|
||||
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
|
||||
throw new IllegalStateException("Couldn't build context for " + descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -782,18 +788,11 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putValueIfNeeded(
|
||||
@NotNull Type parameterType,
|
||||
@NotNull StackValue value
|
||||
) {
|
||||
public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value) {
|
||||
putValueIfNeeded(parameterType, value, -1);
|
||||
}
|
||||
|
||||
private void putValueIfNeeded(
|
||||
@NotNull Type parameterType,
|
||||
@NotNull StackValue value,
|
||||
int index
|
||||
) {
|
||||
private void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, int index) {
|
||||
if (shouldPutValue(parameterType, value)) {
|
||||
value.put(parameterType, codegen.v);
|
||||
}
|
||||
@@ -801,17 +800,14 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putCapturedValueOnStack(
|
||||
@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
|
||||
) {
|
||||
public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
|
||||
if (shouldPutValue(stackValue.type, stackValue)) {
|
||||
stackValue.put(stackValue.type, codegen.v);
|
||||
}
|
||||
putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
|
||||
}
|
||||
|
||||
|
||||
public void generateAndInsertFinallyBlocks(
|
||||
private void generateAndInsertFinallyBlocks(
|
||||
@NotNull MethodNode intoNode,
|
||||
@NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
|
||||
int offsetForFinallyLocalVar
|
||||
@@ -879,7 +875,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
//processor.substituteLocalVarTable(intoNode);
|
||||
}
|
||||
|
||||
public void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
private void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
|
||||
|
||||
InsnList instructions = intoNode.instructions;
|
||||
@@ -898,6 +894,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap, @NotNull SourceMapper parent) {
|
||||
return new NestedSourceMapper(parent, nodeAndSmap.getSortedRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
|
||||
}
|
||||
@@ -912,7 +909,8 @@ public class InlineCodegen extends CallGenerator {
|
||||
if (incrementalCache == null) return;
|
||||
String classFilePath = InlineCodegenUtilsKt.getClassFilePath(sourceDescriptor, state.getTypeMapper(), incrementalCache);
|
||||
String sourceFilePath = InlineCodegenUtilsKt.getSourceFilePath(targetDescriptor);
|
||||
incrementalCache.registerInline(classFilePath, jvmSignature.toString(), sourceFilePath);
|
||||
Method method = jvmSignature.getAsmMethod();
|
||||
incrementalCache.registerInline(classFilePath, method.getName() + method.getDescriptor(), sourceFilePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ class InlineCodegenForDefaultBody(
|
||||
}
|
||||
|
||||
override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) {
|
||||
val nodeAndSmap = InlineCodegen.createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, state)
|
||||
val nodeAndSmap = InlineCodegen.createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault)
|
||||
val childSourceMapper = InlineCodegen.createNestedSourceMapper(nodeAndSmap, sourceMapper)
|
||||
|
||||
val node = nodeAndSmap.node
|
||||
@@ -111,4 +111,4 @@ class InlineCodegenForDefaultBody(
|
||||
override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) {
|
||||
throw UnsupportedOperationException("Shouldn't be called")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen.inline;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import kotlin.text.StringsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile;
|
||||
import org.jetbrains.kotlin.codegen.MemberCodegen;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
@@ -31,7 +29,6 @@ import org.jetbrains.kotlin.codegen.context.CodegenContextUtil;
|
||||
import org.jetbrains.kotlin.codegen.context.InlineLambdaContext;
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt;
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
||||
@@ -63,19 +60,19 @@ public class InlineCodegenUtil {
|
||||
public static final boolean GENERATE_SMAP = true;
|
||||
public static final int API = Opcodes.ASM5;
|
||||
|
||||
public static final String CAPTURED_FIELD_PREFIX = "$";
|
||||
public static final String NON_CAPTURED_FIELD_PREFIX = "$$";
|
||||
private static final String CAPTURED_FIELD_PREFIX = "$";
|
||||
private static final String NON_CAPTURED_FIELD_PREFIX = "$$";
|
||||
public static final String THIS$0 = "this$0";
|
||||
public static final String THIS = "this";
|
||||
public static final String RECEIVER$0 = "receiver$0";
|
||||
public static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$";
|
||||
private static final String RECEIVER$0 = "receiver$0";
|
||||
private static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$";
|
||||
public static final String FIRST_FUN_LABEL = "$$$$$ROOT$$$$$";
|
||||
public static final String NUMBERED_FUNCTION_PREFIX = "kotlin/jvm/functions/Function";
|
||||
public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
|
||||
public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
|
||||
public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
||||
public static final String INLINE_MARKER_FINALLY_START = "finallyStart";
|
||||
public static final String INLINE_MARKER_FINALLY_END = "finallyEnd";
|
||||
private static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
|
||||
private static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
|
||||
private static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
||||
private static final String INLINE_MARKER_FINALLY_START = "finallyStart";
|
||||
private static final String INLINE_MARKER_FINALLY_END = "finallyEnd";
|
||||
public static final String INLINE_TRANSFORMATION_SUFFIX = "$inlined";
|
||||
public static final String INLINE_FUN_THIS_0_SUFFIX = "$inline_fun";
|
||||
public static final String INLINE_FUN_VAR_SUFFIX = "$iv";
|
||||
@@ -93,6 +90,7 @@ public class InlineCodegenUtil {
|
||||
final int[] lines = new int[2];
|
||||
lines[0] = Integer.MAX_VALUE;
|
||||
lines[1] = Integer.MIN_VALUE;
|
||||
//noinspection PointlessBitwiseExpression
|
||||
cr.accept(new ClassVisitor(API) {
|
||||
@Override
|
||||
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
|
||||
@@ -174,7 +172,7 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile findVirtualFileImprecise(@NotNull GenerationState state, @NotNull String internalClassName) {
|
||||
private static VirtualFile findVirtualFileImprecise(@NotNull GenerationState state, @NotNull String internalClassName) {
|
||||
FqName packageFqName = JvmClassName.byInternalName(internalClassName).getPackageFqName();
|
||||
String classNameWithDollars = StringsKt.substringAfterLast(internalClassName, "/", internalClassName);
|
||||
//TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file
|
||||
@@ -182,6 +180,7 @@ public class InlineCodegenUtil {
|
||||
return findVirtualFile(state, new ClassId(packageFqName, Name.identifier(classNameWithDollars)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getInlineName(
|
||||
@NotNull CodegenContext codegenContext,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@@ -190,6 +189,7 @@ public class InlineCodegenUtil {
|
||||
return getInlineName(codegenContext, codegenContext.getContextDescriptor(), typeMapper, fileClassesManager);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getInlineName(
|
||||
@NotNull CodegenContext codegenContext,
|
||||
@NotNull DeclarationDescriptor currentDescriptor,
|
||||
@@ -197,21 +197,24 @@ public class InlineCodegenUtil {
|
||||
@NotNull JvmFileClassesProvider fileClassesProvider
|
||||
) {
|
||||
if (currentDescriptor instanceof PackageFragmentDescriptor) {
|
||||
PsiFile file = getContainingFile(codegenContext);
|
||||
PsiFile file = DescriptorToSourceUtils.getContainingFile(codegenContext.getContextDescriptor());
|
||||
|
||||
Type implementationOwnerType;
|
||||
if (file == null) {
|
||||
implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(codegenContext);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
implementationOwnerType = FileClasses.getFileClassType(fileClassesProvider, (KtFile) file);
|
||||
}
|
||||
|
||||
if (implementationOwnerType == null) {
|
||||
DeclarationDescriptor contextDescriptor = codegenContext.getContextDescriptor();
|
||||
//noinspection ConstantConditions
|
||||
throw new RuntimeException("Couldn't find declaration for " +
|
||||
contextDescriptor.getContainingDeclaration().getName() + "." + contextDescriptor.getName() +
|
||||
"; context: " + codegenContext);
|
||||
throw new RuntimeException(
|
||||
"Couldn't find declaration for " +
|
||||
contextDescriptor.getContainingDeclaration().getName() + "." + contextDescriptor.getName() +
|
||||
"; context: " + codegenContext
|
||||
);
|
||||
}
|
||||
|
||||
return implementationOwnerType.getInternalName();
|
||||
@@ -219,12 +222,12 @@ public class InlineCodegenUtil {
|
||||
else if (currentDescriptor instanceof ClassifierDescriptor) {
|
||||
Type type = typeMapper.mapType((ClassifierDescriptor) currentDescriptor);
|
||||
return type.getInternalName();
|
||||
} else if (currentDescriptor instanceof FunctionDescriptor) {
|
||||
}
|
||||
else if (currentDescriptor instanceof FunctionDescriptor) {
|
||||
ClassDescriptor descriptor =
|
||||
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
|
||||
if (descriptor != null) {
|
||||
Type type = typeMapper.mapType(descriptor);
|
||||
return type.getInternalName();
|
||||
return typeMapper.mapType(descriptor).getInternalName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,14 +249,15 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
|
||||
public static boolean isWhenMappingAccess(@NotNull String internalName, @NotNull String fieldName) {
|
||||
return fieldName.startsWith(WhenByEnumsMapping.MAPPING_ARRAY_FIELD_PREFIX) && internalName.endsWith(WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX);
|
||||
return fieldName.startsWith(WhenByEnumsMapping.MAPPING_ARRAY_FIELD_PREFIX) &&
|
||||
internalName.endsWith(WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX);
|
||||
}
|
||||
|
||||
public static boolean isAnonymousSingletonLoad(@NotNull String internalName, @NotNull String fieldName) {
|
||||
return JvmAbi.INSTANCE_FIELD.equals(fieldName) && isAnonymousClass(internalName);
|
||||
}
|
||||
|
||||
public static boolean isAnonymousClass(String internalName) {
|
||||
public static boolean isAnonymousClass(@NotNull String internalName) {
|
||||
String shortName = getLastNamePart(internalName);
|
||||
int index = shortName.lastIndexOf("$");
|
||||
|
||||
@@ -271,16 +275,6 @@ public class InlineCodegenUtil {
|
||||
return index < 0 ? internalName : internalName.substring(index + 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiFile getContainingFile(CodegenContext codegenContext) {
|
||||
DeclarationDescriptor contextDescriptor = codegenContext.getContextDescriptor();
|
||||
PsiElement psiElement = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor);
|
||||
if (psiElement != null) {
|
||||
return psiElement.getContainingFile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MethodVisitor wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) {
|
||||
return new MaxStackFrameSizeAndLocalsCalculator(API, methodNode.access, methodNode.desc, methodNode);
|
||||
@@ -317,7 +311,8 @@ public class InlineCodegenUtil {
|
||||
return getMarkedReturnLabelOrNull(returnIns) != null;
|
||||
}
|
||||
|
||||
public static @Nullable String getMarkedReturnLabelOrNull(@NotNull AbstractInsnNode returnInsn) {
|
||||
@Nullable
|
||||
public static String getMarkedReturnLabelOrNull(@NotNull AbstractInsnNode returnInsn) {
|
||||
if (!isReturnOpcode(returnInsn.getOpcode())) {
|
||||
return null;
|
||||
}
|
||||
@@ -335,30 +330,33 @@ public class InlineCodegenUtil {
|
||||
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type getReturnType(int opcode) {
|
||||
switch (opcode) {
|
||||
case Opcodes.RETURN: return Type.VOID_TYPE;
|
||||
case Opcodes.IRETURN: return Type.INT_TYPE;
|
||||
case Opcodes.DRETURN: return Type.DOUBLE_TYPE;
|
||||
case Opcodes.FRETURN: return Type.FLOAT_TYPE;
|
||||
case Opcodes.LRETURN: return Type.LONG_TYPE;
|
||||
default: return AsmTypes.OBJECT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull InsnList instructions, @NotNull AbstractInsnNode beforeNode) {
|
||||
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode next = iterator.next();
|
||||
instructions.insertBefore(beforeNode, next);
|
||||
case Opcodes.RETURN:
|
||||
return Type.VOID_TYPE;
|
||||
case Opcodes.IRETURN:
|
||||
return Type.INT_TYPE;
|
||||
case Opcodes.DRETURN:
|
||||
return Type.DOUBLE_TYPE;
|
||||
case Opcodes.FRETURN:
|
||||
return Type.FLOAT_TYPE;
|
||||
case Opcodes.LRETURN:
|
||||
return Type.LONG_TYPE;
|
||||
default:
|
||||
return AsmTypes.OBJECT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode beforeNode) {
|
||||
insertNodeBefore(from, to.instructions, beforeNode);
|
||||
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode next = iterator.next();
|
||||
to.instructions.insertBefore(beforeNode, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static MethodNode createEmptyMethodNode() {
|
||||
return new MethodNode(API, 0, "fake", "()V", null, null);
|
||||
}
|
||||
@@ -374,11 +372,7 @@ public class InlineCodegenUtil {
|
||||
|
||||
@NotNull
|
||||
public static String getNodeText(@Nullable MethodNode node) {
|
||||
return getNodeText(node, new Textifier());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNodeText(@Nullable MethodNode node, @NotNull Textifier textifier) {
|
||||
Textifier textifier = new Textifier();
|
||||
if (node == null) {
|
||||
return "Not generated";
|
||||
}
|
||||
@@ -386,7 +380,7 @@ public class InlineCodegenUtil {
|
||||
StringWriter sw = new StringWriter();
|
||||
textifier.print(new PrintWriter(sw));
|
||||
sw.flush();
|
||||
return node.name + " " + node.desc + ": \n " + sw.getBuffer().toString();
|
||||
return node.name + " " + node.desc + ":\n" + sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -397,13 +391,11 @@ public class InlineCodegenUtil {
|
||||
if (outputFile != null) {
|
||||
return new ClassReader(outputFile.asByteArray());
|
||||
}
|
||||
else {
|
||||
VirtualFile file = findVirtualFileImprecise(state, internalName);
|
||||
if (file == null) {
|
||||
throw new RuntimeException("Couldn't find virtual file for " + internalName);
|
||||
}
|
||||
VirtualFile file = findVirtualFileImprecise(state, internalName);
|
||||
if (file != null) {
|
||||
return new ClassReader(file.contentsToByteArray());
|
||||
}
|
||||
throw new RuntimeException("Couldn't find virtual file for " + internalName);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -424,10 +416,10 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
|
||||
public static boolean isFinallyMarker(@Nullable AbstractInsnNode node) {
|
||||
return isFinallyMarker(node, INLINE_MARKER_FINALLY_END) || isFinallyMarker(node, INLINE_MARKER_FINALLY_START);
|
||||
return node != null && (isFinallyStart(node) || isFinallyEnd(node));
|
||||
}
|
||||
|
||||
public static boolean isFinallyMarker(@Nullable AbstractInsnNode node, String name) {
|
||||
private static boolean isFinallyMarker(@NotNull AbstractInsnNode node, String name) {
|
||||
if (!(node instanceof MethodInsnNode)) return false;
|
||||
MethodInsnNode method = (MethodInsnNode) node;
|
||||
return INLINE_MARKER_CLASS_NAME.equals(method.owner) && name.equals(method.name);
|
||||
@@ -437,69 +429,51 @@ public class InlineCodegenUtil {
|
||||
return context.isInlineMethodContext() || context instanceof InlineLambdaContext;
|
||||
}
|
||||
|
||||
public static int getConstant(AbstractInsnNode ins) {
|
||||
public static int getConstant(@NotNull AbstractInsnNode ins) {
|
||||
int opcode = ins.getOpcode();
|
||||
Integer value;
|
||||
if (opcode >= Opcodes.ICONST_0 && opcode <= Opcodes.ICONST_5) {
|
||||
value = opcode - Opcodes.ICONST_0;
|
||||
return opcode - Opcodes.ICONST_0;
|
||||
}
|
||||
else if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) {
|
||||
IntInsnNode index = (IntInsnNode) ins;
|
||||
value = index.operand;
|
||||
return ((IntInsnNode) ins).operand;
|
||||
}
|
||||
else {
|
||||
LdcInsnNode index = (LdcInsnNode) ins;
|
||||
value = (Integer) index.cst;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static class LabelTextifier extends Textifier {
|
||||
|
||||
public LabelTextifier() {
|
||||
super(API);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@TestOnly
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public String getLabelNameIfExists(@NotNull Label l) {
|
||||
return labelNames == null ? null : labelNames.get(l);
|
||||
return (Integer) index.cst;
|
||||
}
|
||||
}
|
||||
|
||||
public static void addInlineMarker(
|
||||
@NotNull InstructionAdapter v,
|
||||
boolean isStartNotEnd
|
||||
) {
|
||||
v.visitMethodInsn(Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||
(isStartNotEnd ? INLINE_MARKER_BEFORE_METHOD_NAME : INLINE_MARKER_AFTER_METHOD_NAME),
|
||||
"()V", false);
|
||||
public static void addInlineMarker(@NotNull InstructionAdapter v, boolean isStartNotEnd) {
|
||||
v.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||
isStartNotEnd ? INLINE_MARKER_BEFORE_METHOD_NAME : INLINE_MARKER_AFTER_METHOD_NAME,
|
||||
"()V", false
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean isInlineMarker(AbstractInsnNode insn) {
|
||||
public static boolean isInlineMarker(@NotNull AbstractInsnNode insn) {
|
||||
return isInlineMarker(insn, null);
|
||||
}
|
||||
|
||||
public static boolean isInlineMarker(AbstractInsnNode insn, String name) {
|
||||
if (insn instanceof MethodInsnNode) {
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
methodInsnNode.owner.equals(INLINE_MARKER_CLASS_NAME) &&
|
||||
(name != null ? methodInsnNode.name.equals(name)
|
||||
: methodInsnNode.name.equals(INLINE_MARKER_BEFORE_METHOD_NAME) ||
|
||||
methodInsnNode.name.equals(INLINE_MARKER_AFTER_METHOD_NAME));
|
||||
}
|
||||
else {
|
||||
private static boolean isInlineMarker(@NotNull AbstractInsnNode insn, @Nullable String name) {
|
||||
if (!(insn instanceof MethodInsnNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
methodInsnNode.owner.equals(INLINE_MARKER_CLASS_NAME) &&
|
||||
(name != null ? methodInsnNode.name.equals(name)
|
||||
: methodInsnNode.name.equals(INLINE_MARKER_BEFORE_METHOD_NAME) ||
|
||||
methodInsnNode.name.equals(INLINE_MARKER_AFTER_METHOD_NAME));
|
||||
}
|
||||
|
||||
public static boolean isBeforeInlineMarker(AbstractInsnNode insn) {
|
||||
public static boolean isBeforeInlineMarker(@NotNull AbstractInsnNode insn) {
|
||||
return isInlineMarker(insn, INLINE_MARKER_BEFORE_METHOD_NAME);
|
||||
}
|
||||
|
||||
public static boolean isAfterInlineMarker(AbstractInsnNode insn) {
|
||||
public static boolean isAfterInlineMarker(@NotNull AbstractInsnNode insn) {
|
||||
return isInlineMarker(insn, INLINE_MARKER_AFTER_METHOD_NAME);
|
||||
}
|
||||
|
||||
@@ -511,44 +485,27 @@ public class InlineCodegenUtil {
|
||||
return opcode >= Opcodes.ISTORE && opcode <= Opcodes.ASTORE;
|
||||
}
|
||||
|
||||
public static int calcMarkerShift(Parameters parameters, MethodNode node) {
|
||||
public static int calcMarkerShift(@NotNull Parameters parameters, @NotNull MethodNode node) {
|
||||
int markerShiftTemp = getIndexAfterLastMarker(node);
|
||||
return markerShiftTemp - parameters.getRealArgsSizeOnStack() + parameters.getArgsSizeOnStack();
|
||||
}
|
||||
|
||||
protected static int getIndexAfterLastMarker(MethodNode node) {
|
||||
int markerShiftTemp = -1;
|
||||
private static int getIndexAfterLastMarker(@NotNull MethodNode node) {
|
||||
int result = -1;
|
||||
for (LocalVariableNode variable : node.localVariables) {
|
||||
if (isFakeLocalVariableForInline(variable.name)) {
|
||||
markerShiftTemp = Math.max(markerShiftTemp, variable.index + 1);
|
||||
result = Math.max(result, variable.index + 1);
|
||||
}
|
||||
}
|
||||
return markerShiftTemp;
|
||||
}
|
||||
|
||||
public static boolean isFakeLocalVariableForInline(@NotNull String name) {
|
||||
return name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) || name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT);
|
||||
}
|
||||
|
||||
public static boolean isThis0(String name) {
|
||||
return THIS$0.equals(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AbstractInsnNode getPrevMeaningful(@NotNull AbstractInsnNode node) {
|
||||
AbstractInsnNode result = node.getPrevious();
|
||||
while (result != null && !UtilKt.isMeaningful(result)) {
|
||||
result = result.getPrevious();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void removeInterval(@NotNull MethodNode node, @NotNull AbstractInsnNode startInc, @NotNull AbstractInsnNode endInc) {
|
||||
while (startInc != endInc) {
|
||||
AbstractInsnNode next = startInc.getNext();
|
||||
node.instructions.remove(startInc);
|
||||
startInc = next;
|
||||
}
|
||||
node.instructions.remove(startInc);
|
||||
public static boolean isFakeLocalVariableForInline(@NotNull String name) {
|
||||
return name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) ||
|
||||
name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT);
|
||||
}
|
||||
|
||||
public static boolean isThis0(@NotNull String name) {
|
||||
return THIS$0.equals(name);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -24,7 +24,6 @@ import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
||||
import java.util.Collection;
|
||||
|
||||
public class InlinedLambdaRemapper extends FieldRemapper {
|
||||
|
||||
public InlinedLambdaRemapper(
|
||||
@NotNull String lambdaInternalName,
|
||||
@NotNull FieldRemapper parent,
|
||||
@@ -34,16 +33,13 @@ public class InlinedLambdaRemapper extends FieldRemapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(@NotNull String fieldOwner, String fieldName, boolean isFolding) {
|
||||
return isFolding && super.canProcess(fieldOwner, fieldName, isFolding);
|
||||
public boolean canProcess(@NotNull String fieldOwner, @NotNull String fieldName, boolean isFolding) {
|
||||
return isFolding && super.canProcess(fieldOwner, fieldName, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CapturedParamInfo findField(
|
||||
@NotNull FieldInsnNode fieldInsnNode,
|
||||
@NotNull Collection<CapturedParamInfo> captured
|
||||
) {
|
||||
public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection<CapturedParamInfo> captured) {
|
||||
return parent.findField(fieldInsnNode, captured);
|
||||
}
|
||||
|
||||
@@ -52,14 +48,12 @@ public class InlinedLambdaRemapper extends FieldRemapper {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) {
|
||||
if (parent.isRoot()) {
|
||||
return super.getFieldForInline(node, prefix);
|
||||
} else {
|
||||
return parent.getFieldForInline(node, prefix);
|
||||
}
|
||||
return parent.getFieldForInline(node, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,87 +25,76 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class InliningContext {
|
||||
|
||||
@Nullable
|
||||
private final InliningContext parent;
|
||||
|
||||
public final Map<Integer, LambdaInfo> expressionMap;
|
||||
|
||||
private final Map<Integer, LambdaInfo> expressionMap;
|
||||
public final GenerationState state;
|
||||
|
||||
public final NameGenerator nameGenerator;
|
||||
|
||||
public final TypeRemapper typeRemapper;
|
||||
|
||||
public final ReifiedTypeInliner reifedTypeInliner;
|
||||
|
||||
public final ReifiedTypeInliner reifiedTypeInliner;
|
||||
public final boolean isInliningLambda;
|
||||
|
||||
public final boolean classRegeneration;
|
||||
|
||||
protected InliningContext(
|
||||
public InliningContext(
|
||||
@Nullable InliningContext parent,
|
||||
@NotNull Map<Integer, LambdaInfo> map,
|
||||
@NotNull Map<Integer, LambdaInfo> expressionMap,
|
||||
@NotNull GenerationState state,
|
||||
@NotNull NameGenerator nameGenerator,
|
||||
@NotNull TypeRemapper typeRemapper,
|
||||
@NotNull ReifiedTypeInliner reifedTypeInliner,
|
||||
@NotNull ReifiedTypeInliner reifiedTypeInliner,
|
||||
boolean isInliningLambda,
|
||||
boolean classRegeneration
|
||||
) {
|
||||
this.parent = parent;
|
||||
expressionMap = map;
|
||||
this.expressionMap = expressionMap;
|
||||
this.state = state;
|
||||
this.nameGenerator = nameGenerator;
|
||||
this.typeRemapper = typeRemapper;
|
||||
this.reifedTypeInliner = reifedTypeInliner;
|
||||
this.reifiedTypeInliner = reifiedTypeInliner;
|
||||
this.isInliningLambda = isInliningLambda;
|
||||
this.classRegeneration = classRegeneration;
|
||||
}
|
||||
|
||||
public InliningContext subInline(NameGenerator generator) {
|
||||
return subInline(generator, Collections.<String, String>emptyMap());
|
||||
@NotNull
|
||||
public InliningContext subInline(@NotNull NameGenerator generator) {
|
||||
return subInline(generator, Collections.<String, String>emptyMap(), isInliningLambda);
|
||||
}
|
||||
|
||||
public InliningContext subInlineLambda(LambdaInfo lambdaInfo) {
|
||||
@NotNull
|
||||
public InliningContext subInlineLambda(@NotNull LambdaInfo lambdaInfo) {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put(lambdaInfo.getLambdaClassType().getInternalName(), null); //mark lambda inlined
|
||||
return subInline(nameGenerator.subGenerator("lambda"), map, true);
|
||||
}
|
||||
|
||||
private InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
|
||||
return subInline(generator, additionalTypeMappings, isInliningLambda);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InliningContext subInlineWithClassRegeneration(
|
||||
@NotNull NameGenerator generator,
|
||||
@NotNull Map<String, String> newTypeMappings,
|
||||
@NotNull InlineCallSiteInfo callSiteInfo
|
||||
) {
|
||||
return new RegeneratedClassContext(this, expressionMap, state, generator,
|
||||
TypeRemapper.createFrom(typeRemapper, newTypeMappings),
|
||||
reifedTypeInliner, isInliningLambda, callSiteInfo);
|
||||
}
|
||||
|
||||
public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings, boolean isInliningLambda) {
|
||||
return subInline(generator, additionalTypeMappings, isInliningLambda, classRegeneration);
|
||||
return new RegeneratedClassContext(
|
||||
this, expressionMap, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
|
||||
reifiedTypeInliner, isInliningLambda, callSiteInfo
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private InliningContext subInline(
|
||||
NameGenerator generator,
|
||||
Map<String, String> additionalTypeMappings,
|
||||
boolean isInliningLambda,
|
||||
boolean isRegeneration
|
||||
@NotNull NameGenerator generator, @NotNull Map<String, String> additionalTypeMappings, boolean isInliningLambda
|
||||
) {
|
||||
//isInliningLambda && !this.isInliningLambda for root inline lambda
|
||||
return new InliningContext(this, expressionMap, state, generator,
|
||||
TypeRemapper.createFrom(
|
||||
typeRemapper,
|
||||
additionalTypeMappings,
|
||||
//root inline lambda
|
||||
isInliningLambda && !this.isInliningLambda
|
||||
),
|
||||
reifedTypeInliner, isInliningLambda, isRegeneration);
|
||||
return new InliningContext(
|
||||
this, expressionMap, state, generator,
|
||||
TypeRemapper.createFrom(
|
||||
typeRemapper,
|
||||
additionalTypeMappings,
|
||||
//root inline lambda
|
||||
isInliningLambda && !this.isInliningLambda
|
||||
),
|
||||
reifiedTypeInliner, isInliningLambda, classRegeneration
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
@@ -114,12 +103,8 @@ public class InliningContext {
|
||||
|
||||
@NotNull
|
||||
public RootInliningContext getRoot() {
|
||||
if (isRoot()) {
|
||||
return (RootInliningContext) this;
|
||||
}
|
||||
else {
|
||||
return parent.getRoot();
|
||||
}
|
||||
//noinspection ConstantConditions
|
||||
return isRoot() ? (RootInliningContext) this : parent.getRoot();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -127,11 +112,7 @@ public class InliningContext {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public boolean isInliningLambdaRootContext() {
|
||||
//noinspection ConstantConditions
|
||||
return isInliningLambda && !getParent().isInliningLambda;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InlineCallSiteInfo getCallSiteInfo() {
|
||||
assert parent != null : "At least root context should return proper value";
|
||||
return parent.getCallSiteInfo();
|
||||
|
||||
@@ -40,36 +40,26 @@ import java.util.Set;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
|
||||
public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
|
||||
public final KtExpression expression;
|
||||
|
||||
private final KotlinTypeMapper typeMapper;
|
||||
|
||||
@NotNull
|
||||
public final Set<String> labels;
|
||||
|
||||
private final CalculatedClosure closure;
|
||||
|
||||
public final boolean isCrossInline;
|
||||
|
||||
private SMAPAndMethodNode node;
|
||||
|
||||
private List<CapturedParamDesc> capturedVars;
|
||||
|
||||
private final FunctionDescriptor functionDescriptor;
|
||||
|
||||
private final ClassDescriptor classDescriptor;
|
||||
|
||||
private final Type closureClassType;
|
||||
|
||||
LambdaInfo(@NotNull KtExpression expr, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline) {
|
||||
private SMAPAndMethodNode node;
|
||||
private List<CapturedParamDesc> capturedVars;
|
||||
|
||||
public LambdaInfo(@NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline) {
|
||||
this.isCrossInline = isCrossInline;
|
||||
this.expression = expr instanceof KtLambdaExpression ?
|
||||
((KtLambdaExpression) expr).getFunctionLiteral() : expr;
|
||||
this.expression = expression instanceof KtLambdaExpression ?
|
||||
((KtLambdaExpression) expression).getFunctionLiteral() : expression;
|
||||
|
||||
this.typeMapper = typeMapper;
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression);
|
||||
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, this.expression);
|
||||
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
|
||||
|
||||
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
|
||||
@@ -78,34 +68,39 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
closure = bindingContext.get(CLOSURE, classDescriptor);
|
||||
assert closure != null : "Closure for lambda should be not null " + expression.getText();
|
||||
|
||||
|
||||
labels = InlineCodegen.getDeclarationLabels(expr, functionDescriptor);
|
||||
labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SMAPAndMethodNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public void setNode(SMAPAndMethodNode node) {
|
||||
public void setNode(@NotNull SMAPAndMethodNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionDescriptor getFunctionDescriptor() {
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KtExpression getFunctionWithBodyOrCallableReference() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor getClassDescriptor() {
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type getLambdaClassType() {
|
||||
return closureClassType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<CapturedParamDesc> getCapturedVars() {
|
||||
//lazy initialization cause it would be calculated after object creation
|
||||
if (capturedVars == null) {
|
||||
@@ -114,11 +109,12 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
if (closure.getCaptureThis() != null) {
|
||||
Type type = typeMapper.mapType(closure.getCaptureThis());
|
||||
EnclosedValueDescriptor descriptor =
|
||||
new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD,
|
||||
null,
|
||||
StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false,
|
||||
StackValue.LOCAL_0),
|
||||
type);
|
||||
new EnclosedValueDescriptor(
|
||||
AsmUtil.CAPTURED_THIS_FIELD,
|
||||
/* descriptor = */ null,
|
||||
StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
|
||||
type
|
||||
);
|
||||
capturedVars.add(getCapturedParamInfo(descriptor));
|
||||
}
|
||||
|
||||
@@ -127,10 +123,10 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
EnclosedValueDescriptor descriptor =
|
||||
new EnclosedValueDescriptor(
|
||||
AsmUtil.CAPTURED_RECEIVER_FIELD,
|
||||
null,
|
||||
StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false,
|
||||
StackValue.LOCAL_0),
|
||||
type);
|
||||
/* descriptor = */ null,
|
||||
StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0),
|
||||
type
|
||||
);
|
||||
capturedVars.add(getCapturedParamInfo(descriptor));
|
||||
}
|
||||
|
||||
@@ -143,29 +139,29 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
|
||||
@NotNull
|
||||
private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
|
||||
return CapturedParamDesc.createDesc(this, descriptor.getFieldName(), descriptor.getType());
|
||||
return new CapturedParamDesc(this, descriptor.getFieldName(), descriptor.getType());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Type> getInvokeParamsWithoutCaptured() {
|
||||
Type[] types = typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes();
|
||||
return Arrays.asList(types);
|
||||
return Arrays.asList(typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Parameters addAllParameters(FieldRemapper remapper) {
|
||||
public Parameters addAllParameters(@NotNull FieldRemapper remapper) {
|
||||
Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor());
|
||||
ParametersBuilder builder =
|
||||
ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this);
|
||||
ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this);
|
||||
|
||||
for (CapturedParamDesc info : getCapturedVars()) {
|
||||
CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
|
||||
assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName();
|
||||
builder.addCapturedParam(field, info.getFieldName());
|
||||
}
|
||||
|
||||
return builder.buildParameters();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Type getType() {
|
||||
return closureClassType;
|
||||
@@ -175,6 +171,4 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
public boolean isMyLabel(@NotNull String name) {
|
||||
return labels.contains(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -28,18 +28,16 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import static org.jetbrains.kotlin.codegen.inline.LocalVarRemapper.RemapStatus.*;
|
||||
|
||||
public class LocalVarRemapper {
|
||||
|
||||
private final Parameters params;
|
||||
private final int actualParamsSize;
|
||||
|
||||
private final StackValue[] remapValues;
|
||||
private final int additionalShift;
|
||||
|
||||
public LocalVarRemapper(Parameters params, int additionalShift) {
|
||||
public LocalVarRemapper(@NotNull Parameters params, int additionalShift) {
|
||||
this.additionalShift = additionalShift;
|
||||
this.params = params;
|
||||
|
||||
remapValues = new StackValue [params.getArgsSizeOnStack()];
|
||||
remapValues = new StackValue[params.getArgsSizeOnStack()];
|
||||
|
||||
int realSize = 0;
|
||||
for (ParameterInfo info : params) {
|
||||
@@ -56,7 +54,8 @@ public class LocalVarRemapper {
|
||||
actualParamsSize = realSize;
|
||||
}
|
||||
|
||||
public RemapInfo doRemap(int index) {
|
||||
@NotNull
|
||||
private RemapInfo doRemap(int index) {
|
||||
int remappedIndex;
|
||||
|
||||
if (index < params.getArgsSizeOnStack()) {
|
||||
@@ -67,16 +66,20 @@ public class LocalVarRemapper {
|
||||
}
|
||||
if (info.isRemapped()) {
|
||||
return new RemapInfo(remapped, info, REMAPPED);
|
||||
} else {
|
||||
remappedIndex = ((StackValue.Local)remapped).index;
|
||||
}
|
||||
} else {
|
||||
remappedIndex = actualParamsSize - params.getArgsSizeOnStack() + index; //captured params not used directly in this inlined method, they used in closure
|
||||
else {
|
||||
remappedIndex = ((StackValue.Local) remapped).index;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//captured params are not used directly in this inlined method, they are used in closure
|
||||
remappedIndex = actualParamsSize - params.getArgsSizeOnStack() + index;
|
||||
}
|
||||
|
||||
return new RemapInfo(StackValue.local(remappedIndex + additionalShift, AsmTypes.OBJECT_TYPE), null, SHIFT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RemapInfo remap(int index) {
|
||||
RemapInfo info = doRemap(index);
|
||||
if (FAIL == info.status) {
|
||||
@@ -86,23 +89,29 @@ public class LocalVarRemapper {
|
||||
return info;
|
||||
}
|
||||
|
||||
public void visitIincInsn(int var, int increment, MethodVisitor mv) {
|
||||
public void visitIincInsn(int var, int increment, @NotNull MethodVisitor mv) {
|
||||
RemapInfo remap = remap(var);
|
||||
assert remap.value instanceof StackValue.Local;
|
||||
assert remap.value instanceof StackValue.Local : "Remapped value should be a local: " + remap.value;
|
||||
mv.visitIincInsn(((StackValue.Local) remap.value).index, increment);
|
||||
}
|
||||
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index, MethodVisitor mv) {
|
||||
public void visitLocalVariable(
|
||||
@NotNull String name,
|
||||
@NotNull String desc,
|
||||
@Nullable String signature,
|
||||
@NotNull Label start,
|
||||
@NotNull Label end,
|
||||
int index,
|
||||
MethodVisitor mv
|
||||
) {
|
||||
RemapInfo info = doRemap(index);
|
||||
//add entries only for shifted vars
|
||||
if (SHIFT == info.status) {
|
||||
int newIndex = ((StackValue.Local) info.value).index;
|
||||
mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
|
||||
mv.visitLocalVariable(name, desc, signature, start, end, ((StackValue.Local) info.value).index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void visitVarInsn(int opcode, int var, InstructionAdapter mv) {
|
||||
public void visitVarInsn(int opcode, int var, @NotNull InstructionAdapter mv) {
|
||||
RemapInfo remapInfo = remap(var);
|
||||
StackValue value = remapInfo.value;
|
||||
if (value instanceof StackValue.Local) {
|
||||
@@ -117,7 +126,8 @@ public class LocalVarRemapper {
|
||||
if (remapInfo.parameterInfo != null) {
|
||||
StackValue.coerce(value.type, remapInfo.parameterInfo.type, mv);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
assert remapInfo.parameterInfo != null : "Non local value should have parameter info";
|
||||
value.put(remapInfo.parameterInfo.type, mv);
|
||||
}
|
||||
@@ -134,15 +144,15 @@ public class LocalVarRemapper {
|
||||
public final ParameterInfo parameterInfo;
|
||||
public final RemapStatus status;
|
||||
|
||||
public RemapInfo(@NotNull StackValue value, @Nullable ParameterInfo info, RemapStatus remapStatus) {
|
||||
public RemapInfo(@NotNull StackValue value, @Nullable ParameterInfo parameterInfo, @NotNull RemapStatus remapStatus) {
|
||||
this.value = value;
|
||||
parameterInfo = info;
|
||||
this.parameterInfo = parameterInfo;
|
||||
this.status = remapStatus;
|
||||
}
|
||||
|
||||
public RemapInfo(@NotNull ParameterInfo info) {
|
||||
public RemapInfo(@NotNull ParameterInfo parameterInfo) {
|
||||
this.value = null;
|
||||
parameterInfo = info;
|
||||
this.parameterInfo = parameterInfo;
|
||||
this.status = FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class MethodBodyVisitor extends InstructionAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
public void visitAttribute(@NotNull Attribute attr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,45 +43,24 @@ import java.util.*;
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*;
|
||||
|
||||
public class MethodInliner {
|
||||
|
||||
private final MethodNode node;
|
||||
|
||||
private final Parameters parameters;
|
||||
|
||||
private final InliningContext inliningContext;
|
||||
|
||||
private final FieldRemapper nodeRemapper;
|
||||
|
||||
private final boolean isSameModule;
|
||||
|
||||
private final String errorPrefix;
|
||||
|
||||
private final SourceMapper sourceMapper;
|
||||
|
||||
private final InlineCallSiteInfo inlineCallSiteInfo;
|
||||
|
||||
private final KotlinTypeMapper typeMapper;
|
||||
|
||||
private final List<InvokeCall> invokeCalls = new ArrayList<InvokeCall>();
|
||||
|
||||
//keeps order
|
||||
private final List<TransformationInfo> transformations = new ArrayList<TransformationInfo>();
|
||||
//current state
|
||||
private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
|
||||
|
||||
private final InlineResult result;
|
||||
|
||||
private int lambdasFinallyBlocks;
|
||||
|
||||
private final InlineOnlySmapSkipper inlineOnlySmapSkipper;
|
||||
|
||||
/*
|
||||
*
|
||||
* @param node
|
||||
* @param parameters
|
||||
* @param inliningContext
|
||||
* @param lambdaType - in case on lambda 'invoke' inlining
|
||||
*/
|
||||
public MethodInliner(
|
||||
@NotNull MethodNode node,
|
||||
@NotNull Parameters parameters,
|
||||
@@ -106,6 +85,7 @@ public class MethodInliner {
|
||||
this.inlineOnlySmapSkipper = smapSkipper;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InlineResult doInline(
|
||||
@NotNull MethodVisitor adapter,
|
||||
@NotNull LocalVarRemapper remapper,
|
||||
@@ -115,6 +95,7 @@ public class MethodInliner {
|
||||
return doInline(adapter, remapper, remapReturn, labelOwner, 0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private InlineResult doInline(
|
||||
@NotNull MethodVisitor adapter,
|
||||
@NotNull LocalVarRemapper remapper,
|
||||
@@ -129,11 +110,12 @@ public class MethodInliner {
|
||||
Label end = new Label();
|
||||
transformedNode = doInline(transformedNode);
|
||||
removeClosureAssertions(transformedNode);
|
||||
InsnList instructions = transformedNode.instructions;
|
||||
instructions.resetLabels();
|
||||
transformedNode.instructions.resetLabels();
|
||||
|
||||
MethodNode resultNode = new MethodNode(InlineCodegenUtil.API, transformedNode.access, transformedNode.name, transformedNode.desc,
|
||||
transformedNode.signature, ArrayUtil.toStringArray(transformedNode.exceptions));
|
||||
MethodNode resultNode = new MethodNode(
|
||||
InlineCodegenUtil.API, transformedNode.access, transformedNode.name, transformedNode.desc,
|
||||
transformedNode.signature, ArrayUtil.toStringArray(transformedNode.exceptions)
|
||||
);
|
||||
RemapVisitor visitor = new RemapVisitor(resultNode, remapper, nodeRemapper);
|
||||
try {
|
||||
transformedNode.accept(visitor);
|
||||
@@ -145,7 +127,10 @@ public class MethodInliner {
|
||||
resultNode.visitLabel(end);
|
||||
|
||||
if (inliningContext.isRoot()) {
|
||||
InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks, ((StackValue.Local)remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index);
|
||||
StackValue remapValue = remapper.remap(parameters.getArgsSizeOnStack() + 1).value;
|
||||
InternalFinallyBlockInliner.processInlineFunFinallyBlocks(
|
||||
resultNode, lambdasFinallyBlocks, ((StackValue.Local) remapValue).index
|
||||
);
|
||||
}
|
||||
|
||||
processReturns(resultNode, labelOwner, remapReturn, end);
|
||||
@@ -156,8 +141,8 @@ public class MethodInliner {
|
||||
return result;
|
||||
}
|
||||
|
||||
private MethodNode doInline(final MethodNode node) {
|
||||
|
||||
@NotNull
|
||||
private MethodNode doInline(@NotNull MethodNode node) {
|
||||
final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);
|
||||
|
||||
final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
|
||||
@@ -174,8 +159,8 @@ public class MethodInliner {
|
||||
|
||||
final int markerShift = InlineCodegenUtil.calcMarkerShift(parameters, node);
|
||||
InlineAdapter lambdaInliner = new InlineAdapter(remappingMethodAdapter, parameters.getArgsSizeOnStack(), sourceMapper) {
|
||||
|
||||
private TransformationInfo transformationInfo;
|
||||
|
||||
private void handleAnonymousObjectRegeneration() {
|
||||
transformationInfo = iterator.next();
|
||||
|
||||
@@ -190,10 +175,7 @@ public class MethodInliner {
|
||||
currentTypeMapping,
|
||||
inlineCallSiteInfo
|
||||
);
|
||||
ObjectTransformer transformer = transformationInfo.createTransformer(
|
||||
childInliningContext,
|
||||
isSameModule
|
||||
);
|
||||
ObjectTransformer transformer = transformationInfo.createTransformer(childInliningContext, isSameModule);
|
||||
|
||||
InlineResult transformResult = transformer.doTransform(nodeRemapper);
|
||||
result.addAllClassesToRemove(transformResult);
|
||||
@@ -213,7 +195,7 @@ public class MethodInliner {
|
||||
|
||||
@Override
|
||||
public void anew(@NotNull Type type) {
|
||||
if (isAnonymousConstructorCall(type.getInternalName(), "<init>")) {
|
||||
if (isAnonymousClass(type.getInternalName())) {
|
||||
handleAnonymousObjectRegeneration();
|
||||
}
|
||||
|
||||
@@ -245,23 +227,25 @@ public class MethodInliner {
|
||||
|
||||
setLambdaInlining(true);
|
||||
SMAP lambdaSMAP = info.getNode().getClassSMAP();
|
||||
//noinspection ConstantConditions
|
||||
SourceMapper mapper =
|
||||
inliningContext.classRegeneration && !inliningContext.isInliningLambda ?
|
||||
new NestedSourceMapper(sourceMapper, lambdaSMAP.getIntervals(), lambdaSMAP.getSourceInfo())
|
||||
inliningContext.classRegeneration && !inliningContext.isInliningLambda
|
||||
? new NestedSourceMapper(sourceMapper, lambdaSMAP.getIntervals(), lambdaSMAP.getSourceInfo())
|
||||
: new InlineLambdaSourceMapper(sourceMapper.getParent(), info.getNode());
|
||||
MethodInliner inliner = new MethodInliner(info.getNode().getNode(), lambdaParameters,
|
||||
inliningContext.subInlineLambda(info),
|
||||
newCapturedRemapper, true /*cause all calls in same module as lambda*/,
|
||||
"Lambda inlining " + info.getLambdaClassType().getInternalName(),
|
||||
mapper, inlineCallSiteInfo, null);
|
||||
MethodInliner inliner = new MethodInliner(
|
||||
info.getNode().getNode(), lambdaParameters, inliningContext.subInlineLambda(info),
|
||||
newCapturedRemapper, true /*cause all calls in same module as lambda*/,
|
||||
"Lambda inlining " + info.getLambdaClassType().getInternalName(),
|
||||
mapper, inlineCallSiteInfo, null
|
||||
);
|
||||
|
||||
LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift);
|
||||
InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift);//TODO add skipped this and receiver
|
||||
//TODO add skipped this and receiver
|
||||
InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift);
|
||||
result.addAllClassesToRemove(lambdaResult);
|
||||
|
||||
//return value boxing/unboxing
|
||||
Method bridge =
|
||||
typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()));
|
||||
Method bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()));
|
||||
Method delegate = typeMapper.mapAsmMethod(info.getFunctionDescriptor());
|
||||
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
|
||||
setLambdaInlining(false);
|
||||
@@ -274,31 +258,38 @@ public class MethodInliner {
|
||||
else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
|
||||
//TODO add proper message
|
||||
assert transformationInfo instanceof AnonymousObjectTransformationInfo :
|
||||
"<init> call doesn't correspond to object transformation info: " + owner + "." + name + ", info " + transformationInfo;
|
||||
"<init> call doesn't correspond to object transformation info: " +
|
||||
owner + "." + name + ", info " + transformationInfo;
|
||||
if (transformationInfo.shouldRegenerate(isSameModule)) {
|
||||
//put additional captured parameters on stack
|
||||
for (CapturedParamDesc capturedParamDesc : ((AnonymousObjectTransformationInfo) transformationInfo).getAllRecapturedParameters()) {
|
||||
visitFieldInsn(Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(),
|
||||
"$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor());
|
||||
AnonymousObjectTransformationInfo info = (AnonymousObjectTransformationInfo) transformationInfo;
|
||||
for (CapturedParamDesc capturedParamDesc : info.getAllRecapturedParameters()) {
|
||||
visitFieldInsn(
|
||||
Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(),
|
||||
"$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor()
|
||||
);
|
||||
}
|
||||
super.visitMethodInsn(opcode, transformationInfo.getNewClassName(), name,
|
||||
((AnonymousObjectTransformationInfo) transformationInfo).getNewConstructorDescriptor(), itf);
|
||||
super.visitMethodInsn(opcode, transformationInfo.getNewClassName(), name, info.getNewConstructorDescriptor(), itf);
|
||||
|
||||
//TODO: add new inner class also for other contexts
|
||||
if (inliningContext.getParent() instanceof RegeneratedClassContext) {
|
||||
inliningContext.getParent().typeRemapper.addAdditionalMappings(transformationInfo.getOldClassName(), transformationInfo.getNewClassName());
|
||||
inliningContext.getParent().typeRemapper.addAdditionalMappings(
|
||||
transformationInfo.getOldClassName(), transformationInfo.getNewClassName()
|
||||
);
|
||||
}
|
||||
|
||||
transformationInfo = null;
|
||||
} else {
|
||||
super.visitMethodInsn(opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf);
|
||||
}
|
||||
else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
}
|
||||
else if (!inliningContext.isInliningLambda && ReifiedTypeInliner.isNeedClassReificationMarker(new MethodInsnNode(opcode, owner, name, desc, false))) {
|
||||
else if (!inliningContext.isInliningLambda &&
|
||||
ReifiedTypeInliner.isNeedClassReificationMarker(new MethodInsnNode(opcode, owner, name, desc, false))) {
|
||||
//we shouldn't process here content of inlining lambda it should be reified at external level
|
||||
}
|
||||
else {
|
||||
super.visitMethodInsn(opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf);
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +306,6 @@ public class MethodInliner {
|
||||
lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
|
||||
super.visitMaxs(stack, locals);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
node.accept(lambdaInliner);
|
||||
@@ -324,18 +314,20 @@ public class MethodInliner {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CapturedParamInfo findCapturedField(FieldInsnNode node, FieldRemapper fieldRemapper) {
|
||||
public static CapturedParamInfo findCapturedField(@NotNull FieldInsnNode node, @NotNull FieldRemapper fieldRemapper) {
|
||||
assert node.name.startsWith("$$$") : "Captured field template should start with $$$ prefix";
|
||||
FieldInsnNode fin = new FieldInsnNode(node.getOpcode(), node.owner, node.name.substring(3), node.desc);
|
||||
CapturedParamInfo field = fieldRemapper.findField(fin);
|
||||
if (field == null) {
|
||||
throw new IllegalStateException("Couldn't find captured field " + node.owner + "." + node.name + " in " + fieldRemapper.getLambdaInternalName());
|
||||
throw new IllegalStateException(
|
||||
"Couldn't find captured field " + node.owner + "." + node.name + " in " + fieldRemapper.getLambdaInternalName()
|
||||
);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodNode prepareNode(@NotNull MethodNode node, int finallyDeepShift) {
|
||||
private MethodNode prepareNode(@NotNull MethodNode node, int finallyDeepShift) {
|
||||
final int capturedParamsSize = parameters.getCapturedArgsSizeOnStack();
|
||||
final int realParametersSize = parameters.getRealArgsSizeOnStack();
|
||||
Type[] types = Type.getArgumentTypes(node.desc);
|
||||
@@ -345,8 +337,10 @@ public class MethodInliner {
|
||||
Type[] allTypes = ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()]));
|
||||
|
||||
node.instructions.resetLabels();
|
||||
MethodNode transformedNode = new MethodNode(InlineCodegenUtil.API, node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null) {
|
||||
|
||||
MethodNode transformedNode = new MethodNode(
|
||||
InlineCodegenUtil.API, node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null
|
||||
) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private final boolean GENERATE_DEBUG_INFO = InlineCodegenUtil.GENERATE_SMAP && inlineOnlySmapSkipper == null;
|
||||
|
||||
private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda();
|
||||
@@ -372,7 +366,7 @@ public class MethodInliner {
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(int line, @NotNull Label start) {
|
||||
if(isInliningLambda || GENERATE_DEBUG_INFO) {
|
||||
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
||||
super.visitLineNumber(line, start);
|
||||
}
|
||||
}
|
||||
@@ -382,9 +376,8 @@ public class MethodInliner {
|
||||
@NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index
|
||||
) {
|
||||
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
||||
String varSuffix = inliningContext.isRoot() &&
|
||||
!InlineCodegenUtil.isFakeLocalVariableForInline(name) ?
|
||||
INLINE_FUN_VAR_SUFFIX : "";
|
||||
String varSuffix =
|
||||
inliningContext.isRoot() && !InlineCodegenUtil.isFakeLocalVariableForInline(name) ? INLINE_FUN_VAR_SUFFIX : "";
|
||||
String varName = !varSuffix.isEmpty() && name.equals("this") ? name + "_" : name;
|
||||
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index));
|
||||
}
|
||||
@@ -400,7 +393,9 @@ public class MethodInliner {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, int finallyDeepShift) {
|
||||
private MethodNode markPlacesForInlineAndRemoveInlinable(
|
||||
@NotNull MethodNode node, @NotNull LabelOwner labelOwner, int finallyDeepShift
|
||||
) {
|
||||
node = prepareNode(node, finallyDeepShift);
|
||||
|
||||
Frame<SourceValue>[] sources = analyzeMethodNodeBeforeInline(node);
|
||||
@@ -460,9 +455,7 @@ public class MethodInliner {
|
||||
}
|
||||
|
||||
transformations.add(
|
||||
buildConstructorInvocation(
|
||||
owner, desc, lambdaMapping, awaitClassReification
|
||||
)
|
||||
buildConstructorInvocation(owner, desc, lambdaMapping, awaitClassReification)
|
||||
);
|
||||
awaitClassReification = false;
|
||||
}
|
||||
@@ -482,7 +475,8 @@ public class MethodInliner {
|
||||
else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
|
||||
transformations.add(
|
||||
new WhenMappingTransformationInfo(
|
||||
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode)
|
||||
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -498,7 +492,8 @@ public class MethodInliner {
|
||||
//NB: Cause we generate exception table for default handler using gaps (see ExpressionCodegen.visitTryExpression)
|
||||
//it may occurs that interval for default handler starts before catch start label, so this label seems as dead,
|
||||
//but as result all this labels will be merged into one (see KT-5863)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
toDelete.add(prevNode);
|
||||
}
|
||||
}
|
||||
@@ -522,6 +517,7 @@ public class MethodInliner {
|
||||
return node;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Frame<SourceValue>[] analyzeMethodNodeBeforeInline(@NotNull MethodNode node) {
|
||||
try {
|
||||
new MandatoryMethodTransformer().transform("fake", node);
|
||||
@@ -545,14 +541,12 @@ public class MethodInliner {
|
||||
}
|
||||
};
|
||||
|
||||
Frame<SourceValue>[] sources;
|
||||
try {
|
||||
sources = analyzer.analyze("fake", node);
|
||||
return analyzer.analyze("fake", node);
|
||||
}
|
||||
catch (AnalyzerException e) {
|
||||
throw wrapException(e, node, "couldn't inline method call");
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
||||
private static boolean isEmptyTryInterval(@NotNull TryCatchBlockNode tryCatchBlockNode) {
|
||||
@@ -595,7 +589,8 @@ public class MethodInliner {
|
||||
int varIndex = ((VarInsnNode) insnNode).var;
|
||||
return getLambdaIfExists(varIndex);
|
||||
}
|
||||
else if (insnNode instanceof FieldInsnNode) {
|
||||
|
||||
if (insnNode instanceof FieldInsnNode) {
|
||||
FieldInsnNode fieldInsnNode = (FieldInsnNode) insnNode;
|
||||
if (fieldInsnNode.name.startsWith("$$$")) {
|
||||
return findCapturedField(fieldInsnNode, nodeRemapper).getLambda();
|
||||
@@ -605,6 +600,7 @@ public class MethodInliner {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LambdaInfo getLambdaIfExists(int varIndex) {
|
||||
if (varIndex < parameters.getArgsSizeOnStack()) {
|
||||
return parameters.getParameterByDeclarationSlot(varIndex).getLambda();
|
||||
@@ -612,13 +608,14 @@ public class MethodInliner {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void removeClosureAssertions(MethodNode node) {
|
||||
private static void removeClosureAssertions(@NotNull MethodNode node) {
|
||||
AbstractInsnNode cur = node.instructions.getFirst();
|
||||
while (cur != null && cur.getNext() != null) {
|
||||
AbstractInsnNode next = cur.getNext();
|
||||
if (next.getType() == AbstractInsnNode.METHOD_INSN) {
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) next;
|
||||
if (methodInsnNode.name.equals("checkParameterIsNotNull") && methodInsnNode.owner.equals(IntrinsicMethods.INTRINSICS_CLASS_NAME)) {
|
||||
if (methodInsnNode.name.equals("checkParameterIsNotNull") &&
|
||||
methodInsnNode.owner.equals(IntrinsicMethods.INTRINSICS_CLASS_NAME)) {
|
||||
AbstractInsnNode prev = cur.getPrevious();
|
||||
|
||||
assert cur.getOpcode() == Opcodes.LDC : "checkParameterIsNotNull should go after LDC but " + cur;
|
||||
@@ -676,7 +673,7 @@ public class MethodInliner {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<AbstractInsnNode> getCapturedFieldAccessChain(@NotNull VarInsnNode aload0) {
|
||||
private static List<AbstractInsnNode> getCapturedFieldAccessChain(@NotNull VarInsnNode aload0) {
|
||||
List<AbstractInsnNode> fieldAccessChain = new ArrayList<AbstractInsnNode>();
|
||||
fieldAccessChain.add(aload0);
|
||||
AbstractInsnNode next = aload0.getNext();
|
||||
@@ -697,7 +694,9 @@ public class MethodInliner {
|
||||
return fieldAccessChain;
|
||||
}
|
||||
|
||||
public static void putStackValuesIntoLocals(List<Type> directOrder, int shift, InstructionAdapter iv, String descriptor) {
|
||||
private static void putStackValuesIntoLocals(
|
||||
@NotNull List<Type> directOrder, int shift, @NotNull InstructionAdapter iv, @NotNull String descriptor
|
||||
) {
|
||||
Type[] actualParams = Type.getArgumentTypes(descriptor);
|
||||
assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
|
||||
|
||||
@@ -719,42 +718,21 @@ public class MethodInliner {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check it's external module
|
||||
//TODO?: assert method exists in facade?
|
||||
public String changeOwnerForExternalPackage(String type, int opcode) {
|
||||
//if (isSameModule || (opcode & Opcodes.INVOKESTATIC) == 0) {
|
||||
// return type;
|
||||
//}
|
||||
|
||||
//JvmClassName name = JvmClassName.byInternalName(type);
|
||||
//String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(name.getPackageFqName());
|
||||
//if (type.startsWith(packageClassInternalName + '$')) {
|
||||
// VirtualFile virtualFile = InlineCodegenUtil.findVirtualFile(inliningContext.state.getProject(), type);
|
||||
// if (virtualFile != null) {
|
||||
// KotlinJvmBinaryClass klass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile);
|
||||
// if (klass != null && klass.getClassHeader().getSyntheticClassKind() == KotlinSyntheticClass.Kind.PACKAGE_PART) {
|
||||
// return packageClassInternalName;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RuntimeException wrapException(@NotNull Throwable originalException, @NotNull MethodNode node, @NotNull String errorSuffix) {
|
||||
private RuntimeException wrapException(@NotNull Throwable originalException, @NotNull MethodNode node, @NotNull String errorSuffix) {
|
||||
if (originalException instanceof InlineException) {
|
||||
return new InlineException(errorPrefix + ": " + errorSuffix, originalException);
|
||||
}
|
||||
else {
|
||||
return new InlineException(errorPrefix + ": " + errorSuffix + "\ncause: " +
|
||||
getNodeText(node), originalException);
|
||||
return new InlineException(errorPrefix + ": " + errorSuffix + "\nCause: " + getNodeText(node), originalException);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
//process local and global returns (local substituted with goto end-label global kept unchanged)
|
||||
public static List<PointForExternalFinallyBlocks> processReturns(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) {
|
||||
public static List<PointForExternalFinallyBlocks> processReturns(
|
||||
@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, @Nullable Label endLabel
|
||||
) {
|
||||
if (!remapReturn) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -785,9 +763,9 @@ public class MethodInliner {
|
||||
//generate finally block before nonLocalReturn flag/return/goto
|
||||
LabelNode label = new LabelNode();
|
||||
instructions.insert(insnNode, label);
|
||||
result.add(new PointForExternalFinallyBlocks(getInstructionToInsertFinallyBefore(insnNode, isLocalReturn),
|
||||
getReturnType(insnNode.getOpcode()),
|
||||
label));
|
||||
result.add(new PointForExternalFinallyBlocks(
|
||||
getInstructionToInsertFinallyBefore(insnNode, isLocalReturn), getReturnType(insnNode.getOpcode()), label
|
||||
));
|
||||
}
|
||||
insnNode = insnNode.getNext();
|
||||
}
|
||||
@@ -860,7 +838,7 @@ public class MethodInliner {
|
||||
}
|
||||
}
|
||||
|
||||
public void transform(MethodNode methodNode) {
|
||||
public void transform(@NotNull MethodNode methodNode) {
|
||||
int returnVariableIndex = -1;
|
||||
if (needsReturnVariable) {
|
||||
returnVariableIndex = methodNode.maxLocals;
|
||||
@@ -872,6 +850,7 @@ public class MethodInliner {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static LocalReturnsNormalizer createFor(
|
||||
@NotNull MethodNode methodNode,
|
||||
@NotNull LabelOwner owner,
|
||||
@@ -905,21 +884,16 @@ public class MethodInliner {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NotNull
|
||||
private static AbstractInsnNode getInstructionToInsertFinallyBefore(@NotNull AbstractInsnNode nonLocalReturnOrJump, boolean isLocal) {
|
||||
private static AbstractInsnNode getInstructionToInsertFinallyBefore(@NotNull AbstractInsnNode nonLocalReturnOrJump, boolean isLocal) {
|
||||
return isLocal ? nonLocalReturnOrJump : nonLocalReturnOrJump.getPrevious();
|
||||
}
|
||||
|
||||
//Place to insert finally blocks from try blocks that wraps inline fun call
|
||||
public static class PointForExternalFinallyBlocks {
|
||||
|
||||
final AbstractInsnNode beforeIns;
|
||||
|
||||
final Type returnType;
|
||||
|
||||
final LabelNode finallyIntervalEnd;
|
||||
public final AbstractInsnNode beforeIns;
|
||||
public final Type returnType;
|
||||
public final LabelNode finallyIntervalEnd;
|
||||
|
||||
public PointForExternalFinallyBlocks(
|
||||
@NotNull AbstractInsnNode beforeIns,
|
||||
@@ -930,6 +904,5 @@ public class MethodInliner {
|
||||
this.returnType = returnType;
|
||||
this.finallyIntervalEnd = finallyIntervalEnd;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
@@ -25,7 +24,6 @@ import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
||||
|
||||
|
||||
fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
insnNode: AbstractInsnNode?,
|
||||
processSwap: Boolean,
|
||||
|
||||
@@ -42,14 +42,13 @@ abstract class ObjectTransformer<out T : TransformationInfo>(@JvmField val trans
|
||||
|
||||
return RemappingClassBuilder(
|
||||
classBuilder,
|
||||
AsmTypeRemapper(inliningContext.typeRemapper, inliningContext.root.typeParameterMappings == null, transformationResult))
|
||||
AsmTypeRemapper(inliningContext.typeRemapper, inliningContext.root.typeParameterMappings == null, transformationResult)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun createClassReader(): ClassReader {
|
||||
return InlineCodegenUtil.buildClassReaderByInternalName(state, transformationInfo.oldClassName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WhenMappingTransformer(
|
||||
@@ -72,7 +71,7 @@ class WhenMappingTransformer(
|
||||
}
|
||||
|
||||
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
||||
return if (name.equals(fieldNode.name)) {
|
||||
return if (name == fieldNode.name) {
|
||||
classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, name, desc, signature, value)
|
||||
}
|
||||
else {
|
||||
@@ -80,18 +79,22 @@ class WhenMappingTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||
val methodNode = MethodNode(access, name, desc, signature, exceptions)
|
||||
methodNodes.add(methodNode)
|
||||
return methodNode
|
||||
override fun visitMethod(
|
||||
access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?
|
||||
): MethodVisitor? {
|
||||
return MethodNode(access, name, desc, signature, exceptions).apply {
|
||||
methodNodes.add(this)
|
||||
}
|
||||
}
|
||||
}, ClassReader.SKIP_FRAMES)
|
||||
|
||||
assert(methodNodes.size == 1, { "When mapping ${fieldNode.owner} class should contain only one method but: " + methodNodes.joinToString { it.name } })
|
||||
assert(methodNodes.size == 1) {
|
||||
"When mapping ${fieldNode.owner} class should contain only one method but: " + methodNodes.joinToString { it.name }
|
||||
}
|
||||
val clinit = methodNodes.first()
|
||||
assert(clinit.name == "<clinit>", { "When mapping should contains only <clinit> method, but contains '${clinit.name}'" })
|
||||
|
||||
var transformedClinit = cutOtherMappings(clinit)
|
||||
val transformedClinit = cutOtherMappings(clinit)
|
||||
val result = classBuilder.newMethod(
|
||||
JvmDeclarationOrigin.NO_ORIGIN, transformedClinit.access, transformedClinit.name, transformedClinit.desc,
|
||||
transformedClinit.signature, transformedClinit.exceptions.toTypedArray()
|
||||
@@ -102,7 +105,6 @@ class WhenMappingTransformer(
|
||||
return transformationResult
|
||||
}
|
||||
|
||||
|
||||
private fun cutOtherMappings(node: MethodNode): MethodNode {
|
||||
val myArrayAccess = InsnSequence(node.instructions).first {
|
||||
it is FieldInsnNode && it.name.equals(transformationInfo.fieldNode.name)
|
||||
@@ -123,9 +125,9 @@ class WhenMappingTransformer(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun isValues(node: AbstractInsnNode) = node is MethodInsnNode &&
|
||||
node.opcode == Opcodes.INVOKESTATIC &&
|
||||
node.name == "values" &&
|
||||
node.desc == "()[" + Type.getObjectType(node.owner).descriptor
|
||||
private fun isValues(node: AbstractInsnNode) =
|
||||
node is MethodInsnNode &&
|
||||
node.opcode == Opcodes.INVOKESTATIC &&
|
||||
node.name == "values" &&
|
||||
node.desc == "()[" + Type.getObjectType(node.owner).descriptor
|
||||
}
|
||||
|
||||
|
||||
@@ -22,28 +22,22 @@ import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
class ParameterInfo {
|
||||
|
||||
protected final int index;
|
||||
|
||||
protected final int declarationIndex;
|
||||
private final int index;
|
||||
public final int declarationIndex;
|
||||
public final Type type;
|
||||
//for skipped parameter: e.g. inlined lambda
|
||||
public final boolean isSkipped;
|
||||
|
||||
private boolean isCaptured;
|
||||
|
||||
public final Type type;
|
||||
|
||||
//for skipped parameter: e.g. inlined lambda
|
||||
public boolean isSkipped;
|
||||
|
||||
private LambdaInfo lambda;
|
||||
//in case when parameter could be extracted from outer context (e.g. from local var)
|
||||
private StackValue remapValue;
|
||||
|
||||
public LambdaInfo lambda;
|
||||
|
||||
ParameterInfo(Type type, boolean skipped, int index, int remapValue, int declarationIndex) {
|
||||
public ParameterInfo(@NotNull Type type, boolean skipped, int index, int remapValue, int declarationIndex) {
|
||||
this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type), declarationIndex);
|
||||
}
|
||||
|
||||
ParameterInfo(@NotNull Type type, boolean skipped, int index, @Nullable StackValue remapValue, int declarationIndex) {
|
||||
public ParameterInfo(@NotNull Type type, boolean skipped, int index, @Nullable StackValue remapValue, int declarationIndex) {
|
||||
this.type = type;
|
||||
this.isSkipped = skipped;
|
||||
this.remapValue = remapValue;
|
||||
@@ -52,7 +46,7 @@ class ParameterInfo {
|
||||
}
|
||||
|
||||
public boolean isSkippedOrRemapped() {
|
||||
return isSkipped || remapValue != null;
|
||||
return isSkipped || isRemapped();
|
||||
}
|
||||
|
||||
public boolean isRemapped() {
|
||||
@@ -68,10 +62,6 @@ class ParameterInfo {
|
||||
return index;
|
||||
}
|
||||
|
||||
public boolean isSkipped() {
|
||||
return isSkipped;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type getType() {
|
||||
return type;
|
||||
@@ -82,12 +72,14 @@ class ParameterInfo {
|
||||
return lambda;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ParameterInfo setLambda(@Nullable LambdaInfo lambda) {
|
||||
this.lambda = lambda;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ParameterInfo setRemapValue(StackValue remapValue) {
|
||||
@NotNull
|
||||
public ParameterInfo setRemapValue(@Nullable StackValue remapValue) {
|
||||
this.remapValue = remapValue;
|
||||
return this;
|
||||
}
|
||||
@@ -96,13 +88,7 @@ class ParameterInfo {
|
||||
return isCaptured;
|
||||
}
|
||||
|
||||
public ParameterInfo setSkipped(boolean skipped) {
|
||||
isSkipped = skipped;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setCaptured(boolean isCaptured) {
|
||||
this.isCaptured = isCaptured;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ internal class Parameters(val real: List<ParameterInfo>, val captured: List<Capt
|
||||
}
|
||||
}
|
||||
|
||||
fun getDeclarationSlot(info : ParameterInfo): Int {
|
||||
fun getDeclarationSlot(info: ParameterInfo): Int {
|
||||
return paramToDeclByteCodeIndex[info]!!
|
||||
}
|
||||
|
||||
@@ -54,10 +54,7 @@ internal class Parameters(val real: List<ParameterInfo>, val captured: List<Capt
|
||||
}
|
||||
|
||||
private fun get(index: Int): ParameterInfo {
|
||||
if (index < real.size) {
|
||||
return real.get(index)
|
||||
}
|
||||
return captured.get(index - real.size)
|
||||
return real.getOrNull(index) ?: captured[index - real.size]
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<ParameterInfo> {
|
||||
@@ -71,7 +68,7 @@ internal class Parameters(val real: List<ParameterInfo>, val captured: List<Capt
|
||||
|
||||
companion object {
|
||||
fun shift(capturedParams: List<CapturedParamInfo>, realSize: Int): List<CapturedParamInfo> {
|
||||
return capturedParams.withIndex().map { it.value.newIndex(it.index+ realSize) }
|
||||
return capturedParams.withIndex().map { it.value.newIndex(it.index + realSize) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,9 @@ package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import java.lang.Deprecated
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
internal class ParametersBuilder private constructor(){
|
||||
import java.util.*
|
||||
|
||||
internal class ParametersBuilder private constructor() {
|
||||
private val valueAndHiddenParams = arrayListOf<ParameterInfo>()
|
||||
private val capturedParams = arrayListOf<CapturedParamInfo>()
|
||||
private var valueParamStart = 0
|
||||
@@ -40,38 +36,31 @@ internal class ParametersBuilder private constructor(){
|
||||
return info
|
||||
}
|
||||
|
||||
fun addNextParameter(type: Type, skipped: Boolean, remapValue: StackValue?): ParameterInfo {
|
||||
return addParameter(ParameterInfo(type, skipped, nextValueParameterIndex, remapValue, valueAndHiddenParams.size))
|
||||
fun addNextParameter(type: Type, skipped: Boolean): ParameterInfo {
|
||||
return addParameter(ParameterInfo(type, skipped, nextValueParameterIndex, null, valueAndHiddenParams.size))
|
||||
}
|
||||
|
||||
fun addNextValueParameter(type: Type, skipped: Boolean, remapValue: StackValue?, parameterIndex: Int): ParameterInfo {
|
||||
return addParameter(ParameterInfo(type, skipped, nextValueParameterIndex, remapValue,
|
||||
if (parameterIndex == -1) valueAndHiddenParams.size else { parameterIndex + valueParamStart }))
|
||||
return addParameter(ParameterInfo(
|
||||
type, skipped, nextValueParameterIndex, remapValue,
|
||||
if (parameterIndex == -1) valueAndHiddenParams.size else parameterIndex + valueParamStart
|
||||
))
|
||||
}
|
||||
|
||||
fun addCapturedParam(
|
||||
original: CapturedParamInfo,
|
||||
newFieldName: String): CapturedParamInfo {
|
||||
val info = CapturedParamInfo(original.desc, newFieldName, original.isSkipped, nextCapturedIndex(), original.getIndex())
|
||||
info.setLambda(original.getLambda())
|
||||
fun addCapturedParam(original: CapturedParamInfo, newFieldName: String): CapturedParamInfo {
|
||||
val info = CapturedParamInfo(original.desc, newFieldName, original.isSkipped, nextCapturedIndex(), original.index)
|
||||
info.lambda = original.lambda
|
||||
return addCapturedParameter(info)
|
||||
}
|
||||
|
||||
private fun nextCapturedIndex(): Int {
|
||||
return nextCaptured
|
||||
private fun nextCapturedIndex(): Int = nextCaptured
|
||||
|
||||
fun addCapturedParam(desc: CapturedParamDesc, newFieldName: String): CapturedParamInfo {
|
||||
return addCapturedParameter(CapturedParamInfo(desc, newFieldName, false, nextCapturedIndex(), null))
|
||||
}
|
||||
|
||||
fun addCapturedParam(
|
||||
desc: CapturedParamDesc,
|
||||
newFieldName: String): CapturedParamInfo {
|
||||
val info = CapturedParamInfo(desc, newFieldName, false, nextCapturedIndex(), null)
|
||||
return addCapturedParameter(info)
|
||||
}
|
||||
|
||||
fun addCapturedParamCopy(
|
||||
copyFrom: CapturedParamInfo): CapturedParamInfo {
|
||||
val info = copyFrom.newIndex(nextCapturedIndex())
|
||||
return addCapturedParameter(info)
|
||||
fun addCapturedParamCopy(copyFrom: CapturedParamInfo): CapturedParamInfo {
|
||||
return addCapturedParameter(copyFrom.newIndex(nextCapturedIndex()))
|
||||
}
|
||||
|
||||
fun addCapturedParam(
|
||||
@@ -80,11 +69,13 @@ internal class ParametersBuilder private constructor(){
|
||||
newFieldName: String,
|
||||
type: Type,
|
||||
skipped: Boolean,
|
||||
original: ParameterInfo?): CapturedParamInfo {
|
||||
val info = CapturedParamInfo(CapturedParamDesc.createDesc(containingLambda, fieldName, type), newFieldName, skipped, nextCapturedIndex(),
|
||||
if (original != null) original.getIndex() else -1)
|
||||
original: ParameterInfo?
|
||||
): CapturedParamInfo {
|
||||
val info = CapturedParamInfo(
|
||||
CapturedParamDesc(containingLambda, fieldName, type), newFieldName, skipped, nextCapturedIndex(), original?.index ?: -1
|
||||
)
|
||||
if (original != null) {
|
||||
info.setLambda(original.getLambda())
|
||||
info.lambda = original.lambda
|
||||
}
|
||||
return addCapturedParameter(info)
|
||||
}
|
||||
@@ -101,7 +92,7 @@ internal class ParametersBuilder private constructor(){
|
||||
return info
|
||||
}
|
||||
|
||||
fun markValueParametesStart(){
|
||||
fun markValueParametersStart() {
|
||||
this.valueParamStart = valueAndHiddenParams.size
|
||||
}
|
||||
|
||||
@@ -119,23 +110,24 @@ internal class ParametersBuilder private constructor(){
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun newBuilder(): ParametersBuilder {
|
||||
return ParametersBuilder()
|
||||
}
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun initializeBuilderFrom(objectType: Type, descriptor: String, inlineLambda: LambdaInfo? = null, addThis: Boolean = true): ParametersBuilder {
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
fun initializeBuilderFrom(
|
||||
objectType: Type, descriptor: String, inlineLambda: LambdaInfo? = null, addThis: Boolean = true
|
||||
): ParametersBuilder {
|
||||
val builder = newBuilder()
|
||||
if (addThis) {
|
||||
//skipped this for inlined lambda cause it will be removed
|
||||
builder.addThis(objectType, inlineLambda != null).setLambda(inlineLambda)
|
||||
builder.addThis(objectType, inlineLambda != null).lambda = inlineLambda
|
||||
}
|
||||
|
||||
val types = Type.getArgumentTypes(descriptor)
|
||||
for (type in types) {
|
||||
builder.addNextParameter(type, false, null)
|
||||
for (type in Type.getArgumentTypes(descriptor)) {
|
||||
builder.addNextParameter(type, false)
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
+3
-1
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import java.util.Map;
|
||||
|
||||
public class RegeneratedClassContext extends InliningContext {
|
||||
private InlineCallSiteInfo callSiteInfo;
|
||||
private final InlineCallSiteInfo callSiteInfo;
|
||||
|
||||
public RegeneratedClassContext(
|
||||
@Nullable InliningContext parent,
|
||||
@@ -39,6 +39,8 @@ public class RegeneratedClassContext extends InliningContext {
|
||||
this.callSiteInfo = callSiteInfo;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public InlineCallSiteInfo getCallSiteInfo() {
|
||||
return callSiteInfo;
|
||||
}
|
||||
|
||||
+22
-17
@@ -34,11 +34,11 @@ public class RegeneratedLambdaFieldRemapper extends FieldRemapper {
|
||||
private final boolean isConstructor;
|
||||
|
||||
public RegeneratedLambdaFieldRemapper(
|
||||
String oldOwnerType,
|
||||
String newOwnerType,
|
||||
Parameters parameters,
|
||||
Map<String, LambdaInfo> recapturedLambdas,
|
||||
FieldRemapper remapper,
|
||||
@NotNull String oldOwnerType,
|
||||
@NotNull String newOwnerType,
|
||||
@NotNull Parameters parameters,
|
||||
@NotNull Map<String, LambdaInfo> recapturedLambdas,
|
||||
@NotNull FieldRemapper remapper,
|
||||
boolean isConstructor
|
||||
) {
|
||||
super(oldOwnerType, remapper, parameters);
|
||||
@@ -50,12 +50,12 @@ public class RegeneratedLambdaFieldRemapper extends FieldRemapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(@NotNull String fieldOwner, String fieldName, boolean isFolding) {
|
||||
public boolean canProcess(@NotNull String fieldOwner, @NotNull String fieldName, boolean isFolding) {
|
||||
return super.canProcess(fieldOwner, fieldName, isFolding) || isRecapturedLambdaType(fieldOwner, isFolding);
|
||||
}
|
||||
|
||||
private boolean isRecapturedLambdaType(String owner, boolean isFolding) {
|
||||
return recapturedLambdas.containsKey(owner) && (isFolding || false == parent instanceof InlinedLambdaRemapper);
|
||||
private boolean isRecapturedLambdaType(@NotNull String owner, boolean isFolding) {
|
||||
return recapturedLambdas.containsKey(owner) && (isFolding || !(parent instanceof InlinedLambdaRemapper));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -64,9 +64,8 @@ public class RegeneratedLambdaFieldRemapper extends FieldRemapper {
|
||||
boolean searchInParent = !canProcess(fieldInsnNode.owner, fieldInsnNode.name, false);
|
||||
if (searchInParent) {
|
||||
return parent.findField(fieldInsnNode);
|
||||
} else {
|
||||
return findFieldInMyCaptured(fieldInsnNode);
|
||||
}
|
||||
return findFieldInMyCaptured(fieldInsnNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,10 +74,11 @@ public class RegeneratedLambdaFieldRemapper extends FieldRemapper {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CapturedParamInfo findFieldInMyCaptured(@NotNull FieldInsnNode fieldInsnNode) {
|
||||
private CapturedParamInfo findFieldInMyCaptured(@NotNull FieldInsnNode fieldInsnNode) {
|
||||
return super.findField(fieldInsnNode, parameters.getCaptured());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getNewLambdaInternalName() {
|
||||
return newOwnerType;
|
||||
@@ -98,18 +98,23 @@ public class RegeneratedLambdaFieldRemapper extends FieldRemapper {
|
||||
|
||||
boolean searchInParent = false;
|
||||
if (field == null) {
|
||||
field = findFieldInMyCaptured(new FieldInsnNode(Opcodes.GETSTATIC, oldOwnerType, "this$0", Type.getObjectType(parent.getLambdaInternalName()).getDescriptor()));
|
||||
field = findFieldInMyCaptured(new FieldInsnNode(
|
||||
Opcodes.GETSTATIC, oldOwnerType, InlineCodegenUtil.THIS$0,
|
||||
Type.getObjectType(parent.getLambdaInternalName()).getDescriptor()
|
||||
));
|
||||
searchInParent = true;
|
||||
if (field == null) {
|
||||
throw new IllegalStateException("Couldn't find captured this " + getLambdaInternalName() + " for " + node.name);
|
||||
}
|
||||
}
|
||||
|
||||
StackValue result = StackValue.field(field.isSkipped ?
|
||||
Type.getObjectType(parent.parent.getNewLambdaInternalName()) : field.getType(),
|
||||
Type.getObjectType(getNewLambdaInternalName()), /*TODO owner type*/
|
||||
field.getNewFieldName(), false,
|
||||
prefix == null ? StackValue.LOCAL_0 : prefix);
|
||||
StackValue result = StackValue.field(
|
||||
field.isSkipped ?
|
||||
Type.getObjectType(parent.parent.getNewLambdaInternalName()) : field.getType(),
|
||||
Type.getObjectType(getNewLambdaInternalName()), /*TODO owner type*/
|
||||
field.getNewFieldName(), false,
|
||||
prefix == null ? StackValue.LOCAL_0 : prefix
|
||||
);
|
||||
|
||||
return searchInParent ? parent.getFieldForInline(node, result) : result;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,8 @@ class ReificationArgument(
|
||||
ReificationArgument(
|
||||
replacement.parameterName,
|
||||
this.nullable || (replacement.nullable && this.arrayDepth == 0),
|
||||
this.arrayDepth + replacement.arrayDepth)
|
||||
this.arrayDepth + replacement.arrayDepth
|
||||
)
|
||||
|
||||
fun reify(replacementAsmType: Type, kotlinType: KotlinType) =
|
||||
Pair(Type.getType("[".repeat(arrayDepth) + replacementAsmType), kotlinType.arrayOf(arrayDepth).makeNullableIfNeeded(nullable))
|
||||
@@ -57,7 +58,6 @@ class ReificationArgument(
|
||||
}
|
||||
|
||||
class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?) {
|
||||
|
||||
enum class OperationKind {
|
||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS;
|
||||
|
||||
@@ -65,8 +65,8 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField val REIFIED_OPERATION_MARKER_METHOD_NAME = "reifiedOperationMarker"
|
||||
@JvmField val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification"
|
||||
const val REIFIED_OPERATION_MARKER_METHOD_NAME = "reifiedOperationMarker"
|
||||
const val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification"
|
||||
|
||||
private fun isOperationReifiedMarker(insn: AbstractInsnNode) =
|
||||
isReifiedMarker(insn) { it == REIFIED_OPERATION_MARKER_METHOD_NAME }
|
||||
@@ -76,10 +76,12 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
return insn.owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && namePredicate(insn.name)
|
||||
}
|
||||
|
||||
@JvmStatic fun isNeedClassReificationMarker(insn: AbstractInsnNode): Boolean =
|
||||
@JvmStatic
|
||||
fun isNeedClassReificationMarker(insn: AbstractInsnNode): Boolean =
|
||||
isReifiedMarker(insn) { s -> s == NEED_CLASS_REIFICATION_MARKER_METHOD_NAME }
|
||||
|
||||
@JvmStatic fun putNeedClassReificationMarker(v: MethodVisitor) {
|
||||
@JvmStatic
|
||||
fun putNeedClassReificationMarker(v: MethodVisitor) {
|
||||
v.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, NEED_CLASS_REIFICATION_MARKER_METHOD_NAME,
|
||||
@@ -102,7 +104,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
|
||||
val instructions = node.instructions
|
||||
maxStackSize = 0
|
||||
var result = ReifiedTypeParametersUsages()
|
||||
val result = ReifiedTypeParametersUsages()
|
||||
for (insn in instructions.toArray()) {
|
||||
if (isOperationReifiedMarker(insn)) {
|
||||
val newName: String? = processReifyMarker(insn as MethodInsnNode, instructions)
|
||||
@@ -144,7 +146,8 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
}
|
||||
|
||||
return null
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
val newReificationArgument = reificationArgument.combine(mapping.reificationArgument!!)
|
||||
instructions.set(insn.previous!!, LdcInsnNode(newReificationArgument.asString()))
|
||||
return mapping.reificationArgument.parameterName
|
||||
@@ -154,43 +157,45 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
private fun processNewArray(insn: MethodInsnNode, parameter: Type) =
|
||||
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
|
||||
|
||||
private fun processAs(insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
safe: Boolean) =
|
||||
rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { stubCheckcast: AbstractInsnNode ->
|
||||
if (stubCheckcast !is TypeInsnNode) return false
|
||||
private fun processAs(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
safe: Boolean
|
||||
) = rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { stubCheckcast: AbstractInsnNode ->
|
||||
if (stubCheckcast !is TypeInsnNode) return false
|
||||
|
||||
val newMethodNode = MethodNode(InlineCodegenUtil.API)
|
||||
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe)
|
||||
val newMethodNode = MethodNode(InlineCodegenUtil.API)
|
||||
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe)
|
||||
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubCheckcast)
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubCheckcast)
|
||||
|
||||
// TODO: refine max stack calculation (it's not always as big as +4)
|
||||
maxStackSize = Math.max(maxStackSize, 4)
|
||||
// TODO: refine max stack calculation (it's not always as big as +4)
|
||||
maxStackSize = Math.max(maxStackSize, 4)
|
||||
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun processIs(insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type) =
|
||||
rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { stubInstanceOf: AbstractInsnNode ->
|
||||
if (stubInstanceOf !is TypeInsnNode) return false
|
||||
private fun processIs(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type
|
||||
) = rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { stubInstanceOf: AbstractInsnNode ->
|
||||
if (stubInstanceOf !is TypeInsnNode) return false
|
||||
|
||||
val newMethodNode = MethodNode(InlineCodegenUtil.API)
|
||||
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
|
||||
val newMethodNode = MethodNode(InlineCodegenUtil.API)
|
||||
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
|
||||
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubInstanceOf)
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubInstanceOf)
|
||||
|
||||
// TODO: refine max stack calculation (it's not always as big as +2)
|
||||
maxStackSize = Math.max(maxStackSize, 2)
|
||||
return true
|
||||
}
|
||||
// TODO: refine max stack calculation (it's not always as big as +2)
|
||||
maxStackSize = Math.max(maxStackSize, 2)
|
||||
return true
|
||||
}
|
||||
|
||||
inline private fun rewriteNextTypeInsn(
|
||||
marker: MethodInsnNode,
|
||||
@@ -214,7 +219,6 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
next.cst = parameter
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val MethodInsnNode.reificationArgument: ReificationArgument?
|
||||
@@ -242,16 +246,18 @@ class TypeParameterMappings() {
|
||||
private val mappingsByName = hashMapOf<String, TypeParameterMapping>()
|
||||
|
||||
fun addParameterMappingToType(name: String, type: KotlinType, asmType: Type, signature: String, isReified: Boolean) {
|
||||
mappingsByName[name] = TypeParameterMapping(name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified)
|
||||
mappingsByName[name] = TypeParameterMapping(
|
||||
name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified
|
||||
)
|
||||
}
|
||||
|
||||
fun addParameterMappingForFurtherReification(name: String, type: KotlinType, reificationArgument: ReificationArgument, isReified: Boolean) {
|
||||
mappingsByName[name] = TypeParameterMapping(name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified)
|
||||
mappingsByName[name] = TypeParameterMapping(
|
||||
name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified
|
||||
)
|
||||
}
|
||||
|
||||
operator fun get(name: String): TypeParameterMapping? {
|
||||
return mappingsByName[name]
|
||||
}
|
||||
operator fun get(name: String): TypeParameterMapping? = mappingsByName[name]
|
||||
|
||||
fun hasReifiedParameters() = mappingsByName.values.any { it.isReified }
|
||||
|
||||
@@ -261,7 +267,8 @@ class TypeParameterMappings() {
|
||||
}
|
||||
|
||||
class TypeParameterMapping(
|
||||
val name: String, val type: KotlinType,
|
||||
val name: String,
|
||||
val type: KotlinType,
|
||||
val asmType: Type?,
|
||||
val reificationArgument: ReificationArgument?,
|
||||
val signature: String?,
|
||||
|
||||
@@ -28,14 +28,14 @@ public class RemapVisitor extends MethodBodyVisitor {
|
||||
private final FieldRemapper nodeRemapper;
|
||||
private final InstructionAdapter instructionAdapter;
|
||||
|
||||
protected RemapVisitor(
|
||||
MethodVisitor mv,
|
||||
LocalVarRemapper localVarRemapper,
|
||||
FieldRemapper nodeRemapper
|
||||
public RemapVisitor(
|
||||
@NotNull MethodVisitor mv,
|
||||
@NotNull LocalVarRemapper remapper,
|
||||
@NotNull FieldRemapper nodeRemapper
|
||||
) {
|
||||
super(mv);
|
||||
this.instructionAdapter = new InstructionAdapter(mv);
|
||||
this.remapper = localVarRemapper;
|
||||
this.remapper = remapper;
|
||||
this.nodeRemapper = nodeRemapper;
|
||||
}
|
||||
|
||||
@@ -58,19 +58,13 @@ public class RemapVisitor extends MethodBodyVisitor {
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
|
||||
if (name.startsWith("$$$")) {
|
||||
if (nodeRemapper instanceof RegeneratedLambdaFieldRemapper || nodeRemapper.isRoot()) {
|
||||
FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc);
|
||||
StackValue inline = nodeRemapper.getFieldForInline(fin, null);
|
||||
assert inline != null : "Captured field should have not null stackValue " + fin;
|
||||
inline.put(inline.type, this);
|
||||
}
|
||||
else {
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
if (name.startsWith("$$$") && (nodeRemapper instanceof RegeneratedLambdaFieldRemapper || nodeRemapper.isRoot())) {
|
||||
FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc);
|
||||
StackValue inline = nodeRemapper.getFieldForInline(fin, null);
|
||||
assert inline != null : "Captured field should have not null stackValue " + fin;
|
||||
inline.put(inline.type, this);
|
||||
return;
|
||||
}
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.psi.KtElement;
|
||||
import java.util.Map;
|
||||
|
||||
public class RootInliningContext extends InliningContext {
|
||||
public final CodegenContext startContext;
|
||||
private final InlineCallSiteInfo inlineCallSiteInfo;
|
||||
public final TypeParameterMappings typeParameterMappings;
|
||||
public final KtElement callElement;
|
||||
@@ -34,7 +33,6 @@ public class RootInliningContext extends InliningContext {
|
||||
@NotNull Map<Integer, LambdaInfo> map,
|
||||
@NotNull GenerationState state,
|
||||
@NotNull NameGenerator nameGenerator,
|
||||
@NotNull CodegenContext startContext,
|
||||
@NotNull KtElement callElement,
|
||||
@NotNull InlineCallSiteInfo classNameToInline,
|
||||
@NotNull ReifiedTypeInliner inliner,
|
||||
@@ -42,11 +40,11 @@ public class RootInliningContext extends InliningContext {
|
||||
) {
|
||||
super(null, map, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), inliner, false, false);
|
||||
this.callElement = callElement;
|
||||
this.startContext = startContext;
|
||||
this.inlineCallSiteInfo = classNameToInline;
|
||||
this.typeParameterMappings = typeParameterMappings;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public InlineCallSiteInfo getCallSiteInfo() {
|
||||
return inlineCallSiteInfo;
|
||||
|
||||
@@ -55,7 +55,9 @@ class SMAPBuilder(
|
||||
val combinedMapping = FileMapping(source, path)
|
||||
realMappings.forEach { fileMapping ->
|
||||
fileMapping.lineMappings.filter { it.callSiteMarker != null }.forEach { rangeMapping ->
|
||||
combinedMapping.addRangeMapping(RangeMapping(rangeMapping.callSiteMarker!!.lineNumber, rangeMapping.dest, rangeMapping.range))
|
||||
combinedMapping.addRangeMapping(RangeMapping(
|
||||
rangeMapping.callSiteMarker!!.lineNumber, rangeMapping.dest, rangeMapping.range
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +97,11 @@ open class NestedSourceMapper(
|
||||
|
||||
if (mappedLineNumber > 0) {
|
||||
return mappedLineNumber
|
||||
} else {
|
||||
val rangeForMapping = (if (lastVisitedRange?.contains(lineNumber) ?: false) lastVisitedRange!! else findMappingIfExists(lineNumber))
|
||||
?: error("Can't find range to map line $lineNumber in ${sourceInfo.source}:${sourceInfo.pathOrCleanFQN}")
|
||||
}
|
||||
else {
|
||||
val rangeForMapping =
|
||||
(if (lastVisitedRange?.contains(lineNumber) ?: false) lastVisitedRange!! else findMappingIfExists(lineNumber))
|
||||
?: error("Can't find range to map line $lineNumber in ${sourceInfo.source}: ${sourceInfo.pathOrCleanFQN}")
|
||||
val sourceLineNumber = rangeForMapping.mapDestToSource(lineNumber)
|
||||
val newLineNumber = parent.mapLineNumber(sourceLineNumber, rangeForMapping.parent!!.name, rangeForMapping.parent!!.path)
|
||||
if (newLineNumber > 0) {
|
||||
@@ -132,9 +136,7 @@ open class InlineLambdaSourceMapper(
|
||||
//don't remap origin lambda line numbers
|
||||
return lineNumber
|
||||
}
|
||||
else {
|
||||
return super.mapLineNumber(lineNumber)
|
||||
}
|
||||
return super.mapLineNumber(lineNumber)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +154,6 @@ interface SourceMapper {
|
||||
}
|
||||
|
||||
fun endMapping() {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -179,11 +180,8 @@ object IdenticalSourceMapper : SourceMapper {
|
||||
class CallSiteMarker(val lineNumber: Int)
|
||||
|
||||
open class DefaultSourceMapper(val sourceInfo: SourceInfo) : SourceMapper {
|
||||
|
||||
private var maxUsedValue: Int = sourceInfo.linesInFile
|
||||
|
||||
private var lastMappedWithChanges: RawFileMapping? = null
|
||||
|
||||
private var fileMappings: LinkedHashMap<String, RawFileMapping> = linkedMapOf()
|
||||
|
||||
protected val origin: RawFileMapping
|
||||
@@ -197,7 +195,6 @@ open class DefaultSourceMapper(val sourceInfo: SourceInfo) : SourceMapper {
|
||||
override val resultMappings: List<FileMapping>
|
||||
get() = fileMappings.values.map { it.toFileMapping() }
|
||||
|
||||
|
||||
init {
|
||||
val name = sourceInfo.source
|
||||
val path = sourceInfo.pathOrCleanFQN
|
||||
@@ -206,8 +203,8 @@ open class DefaultSourceMapper(val sourceInfo: SourceInfo) : SourceMapper {
|
||||
fileMappings.put(createKey(name, path), origin)
|
||||
}
|
||||
|
||||
constructor(sourceInfo: SourceInfo, fileMappings: List<FileMapping>): this(sourceInfo) {
|
||||
fileMappings.asSequence().drop(1)
|
||||
constructor(sourceInfo: SourceInfo, fileMappings: List<FileMapping>) : this(sourceInfo) {
|
||||
fileMappings.asSequence().drop(1)
|
||||
//default one mapped through sourceInfo
|
||||
.forEach { fileMapping ->
|
||||
val newFileMapping = getOrRegisterNewSource(fileMapping.name, fileMapping.path)
|
||||
@@ -227,7 +224,7 @@ open class DefaultSourceMapper(val sourceInfo: SourceInfo) : SourceMapper {
|
||||
override fun mapLineNumber(lineNumber: Int): Int {
|
||||
if (lineNumber < 0) {
|
||||
//no source information, so just skip this linenumber
|
||||
return - 1
|
||||
return -1
|
||||
}
|
||||
//TODO maybe add assertion that linenumber contained in fileMappings
|
||||
return lineNumber
|
||||
@@ -238,8 +235,7 @@ open class DefaultSourceMapper(val sourceInfo: SourceInfo) : SourceMapper {
|
||||
//no source information, so just skip this linenumber
|
||||
return -1
|
||||
}
|
||||
val mappedLineIndex = createMapping(getOrRegisterNewSource(sourceName, sourcePath), source)
|
||||
return mappedLineIndex
|
||||
return createMapping(getOrRegisterNewSource(sourceName, sourcePath), source)
|
||||
}
|
||||
|
||||
private fun createMapping(fileMapping: RawFileMapping, lineNumber: Int): Int {
|
||||
@@ -263,6 +259,7 @@ class SMAP(val fileMappings: List<FileMapping>) {
|
||||
val intervals = fileMappings.flatMap { it.lineMappings }.sortedWith(RangeMapping.Comparator)
|
||||
|
||||
val sourceInfo: SourceInfo
|
||||
|
||||
init {
|
||||
val defaultMapping = default.lineMappings.first()
|
||||
sourceInfo = SourceInfo(default.name, default.path, defaultMapping.source + defaultMapping.range - 1)
|
||||
@@ -349,7 +346,7 @@ data class RangeMapping(val source: Int, val dest: Int, var range: Int = 1, var
|
||||
get() = dest + range - 1
|
||||
|
||||
operator fun contains(destLine: Int): Boolean {
|
||||
return if (skip) true else dest <= destLine && destLine < dest + range
|
||||
return skip || (dest <= destLine && destLine < dest + range)
|
||||
}
|
||||
|
||||
fun mapDestToSource(destLine: Int): Int {
|
||||
@@ -365,12 +362,7 @@ data class RangeMapping(val source: Int, val dest: Int, var range: Int = 1, var
|
||||
if (o1 == o2) return 0
|
||||
|
||||
val res = o1.dest - o2.dest
|
||||
if (res == 0) {
|
||||
return o1.range - o2.range
|
||||
}
|
||||
else {
|
||||
return res
|
||||
}
|
||||
return if (res == 0) o1.range - o2.range else res
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ object SMAPParser {
|
||||
/*only simple mapping now*/
|
||||
val targetSplit = lineMapping.indexOf(':')
|
||||
val originalPart = lineMapping.substring(0, targetSplit)
|
||||
var rangeSeparator = originalPart.indexOf(',').let { if (it < 0) targetSplit else it }
|
||||
val rangeSeparator = originalPart.indexOf(',').let { if (it < 0) targetSplit else it }
|
||||
|
||||
val fileSeparator = lineMapping.indexOf('#')
|
||||
val originalIndex = originalPart.substring(0, fileSeparator).toInt()
|
||||
|
||||
@@ -17,10 +17,8 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||
import java.util.*
|
||||
|
||||
interface TransformationInfo {
|
||||
|
||||
val oldClassName: String
|
||||
|
||||
val newClassName: String
|
||||
@@ -29,10 +27,7 @@ interface TransformationInfo {
|
||||
|
||||
fun canRemoveAfterTransformation(): Boolean
|
||||
|
||||
fun createTransformer(
|
||||
inliningContext: InliningContext,
|
||||
sameModule: Boolean
|
||||
): ObjectTransformer<*>
|
||||
fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*>
|
||||
}
|
||||
|
||||
class WhenMappingTransformationInfo(
|
||||
@@ -41,22 +36,17 @@ class WhenMappingTransformationInfo(
|
||||
val alreadyRegenerated: Boolean,
|
||||
val fieldNode: FieldInsnNode
|
||||
) : TransformationInfo {
|
||||
|
||||
override val newClassName by lazy {
|
||||
nameGenerator.genWhenClassNamePrefix() + TRANSFORMED_WHEN_MAPPING_MARKER + oldClassName.substringAfterLast("/").substringAfterLast(TRANSFORMED_WHEN_MAPPING_MARKER)
|
||||
nameGenerator.genWhenClassNamePrefix() + TRANSFORMED_WHEN_MAPPING_MARKER +
|
||||
oldClassName.substringAfterLast("/").substringAfterLast(TRANSFORMED_WHEN_MAPPING_MARKER)
|
||||
}
|
||||
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean {
|
||||
return !alreadyRegenerated && !sameModule
|
||||
}
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean = !alreadyRegenerated && !sameModule
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean {
|
||||
return true
|
||||
}
|
||||
override fun canRemoveAfterTransformation(): Boolean = true
|
||||
|
||||
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> {
|
||||
return WhenMappingTransformer(this, inliningContext)
|
||||
}
|
||||
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> =
|
||||
WhenMappingTransformer(this, inliningContext)
|
||||
|
||||
companion object {
|
||||
const val TRANSFORMED_WHEN_MAPPING_MARKER = "\$wm$"
|
||||
@@ -71,8 +61,8 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val constructorDesc: String?,
|
||||
private val isStaticOrigin: Boolean,
|
||||
nameGenerator: NameGenerator) : TransformationInfo {
|
||||
|
||||
nameGenerator: NameGenerator
|
||||
) : TransformationInfo {
|
||||
override val newClassName: String by lazy {
|
||||
nameGenerator.genLambdaClassName()
|
||||
}
|
||||
@@ -89,14 +79,10 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
alreadyRegenerated: Boolean,
|
||||
isStaticOrigin: Boolean,
|
||||
nameGenerator: NameGenerator
|
||||
) : this(
|
||||
ownerInternalName, needReification,
|
||||
HashMap<Int, LambdaInfo>(), false, alreadyRegenerated, null, isStaticOrigin, nameGenerator) {
|
||||
}
|
||||
) : this(ownerInternalName, needReification, hashMapOf(), false, alreadyRegenerated, null, isStaticOrigin, nameGenerator)
|
||||
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean {
|
||||
return !alreadyRegenerated && (!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification)
|
||||
}
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean =
|
||||
!alreadyRegenerated && (!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification)
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean {
|
||||
// Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda
|
||||
@@ -104,7 +90,6 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
return !isStaticOrigin
|
||||
}
|
||||
|
||||
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> {
|
||||
return AnonymousObjectTransformer(this, inliningContext, sameModule)
|
||||
}
|
||||
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> =
|
||||
AnonymousObjectTransformer(this, inliningContext, sameModule)
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.firstLabelInChain
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
||||
|
||||
enum class TryCatchPosition {
|
||||
START,
|
||||
@@ -26,9 +26,9 @@ enum class TryCatchPosition {
|
||||
INNER
|
||||
}
|
||||
|
||||
class SplitPair<out T: Interval>(val patchedPart: T, val newPart: T)
|
||||
class SplitPair<out T : Interval>(val patchedPart: T, val newPart: T)
|
||||
|
||||
class SimpleInterval(override val startLabel: LabelNode, override val endLabel: LabelNode ) : Interval
|
||||
class SimpleInterval(override val startLabel: LabelNode, override val endLabel: LabelNode) : Interval
|
||||
|
||||
interface Interval {
|
||||
val startLabel: LabelNode
|
||||
@@ -36,20 +36,21 @@ interface Interval {
|
||||
|
||||
/*note that some intervals are mutable */
|
||||
fun isEmpty(): Boolean = startLabel == endLabel
|
||||
|
||||
}
|
||||
|
||||
interface SplittableInterval<T: Interval> : Interval {
|
||||
interface SplittableInterval<out T : Interval> : Interval {
|
||||
fun split(splitBy: Interval, keepStart: Boolean): SplitPair<T>
|
||||
}
|
||||
|
||||
|
||||
interface IntervalWithHandler : Interval {
|
||||
val handler: LabelNode
|
||||
val type: String?
|
||||
}
|
||||
|
||||
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler, SplittableInterval<TryCatchBlockNodeInfo> {
|
||||
class TryCatchBlockNodeInfo(
|
||||
val node: TryCatchBlockNode,
|
||||
val onlyCopyNotProcess: Boolean
|
||||
) : IntervalWithHandler, SplittableInterval<TryCatchBlockNodeInfo> {
|
||||
override val startLabel: LabelNode
|
||||
get() = node.start
|
||||
override val endLabel: LabelNode
|
||||
@@ -77,16 +78,16 @@ class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess:
|
||||
}
|
||||
}
|
||||
|
||||
class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition) : IntervalWithHandler by nodeInfo {
|
||||
|
||||
}
|
||||
class TryCatchBlockNodePosition(
|
||||
val nodeInfo: TryCatchBlockNodeInfo,
|
||||
var position: TryCatchPosition
|
||||
) : IntervalWithHandler by nodeInfo
|
||||
|
||||
class TryBlockCluster<T : IntervalWithHandler>(val blocks: MutableList<T>) {
|
||||
val defaultHandler: T?
|
||||
get() = blocks.firstOrNull() { it.type == null }
|
||||
}
|
||||
|
||||
|
||||
fun <T : IntervalWithHandler> doClustering(blocks: List<T>): List<TryBlockCluster<T>> {
|
||||
data class TryBlockInterval(val startLabel: LabelNode, val endLabel: LabelNode)
|
||||
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import java.util.HashMap
|
||||
import java.util.*
|
||||
|
||||
class TypeParameter(val oldName: String, val newName: String?, val isReified: Boolean, val signature: String?)
|
||||
class TypeParameter(val oldName: String, val newName: String?, val isReified: Boolean, val signature: String?)
|
||||
|
||||
//typeMapping data could be changed outside through method processing
|
||||
class TypeRemapper private constructor(private val typeMapping: MutableMap<String, String>, val parent: TypeRemapper?, val isInlineLambda: Boolean = false) {
|
||||
|
||||
class TypeRemapper private constructor(
|
||||
private val typeMapping: MutableMap<String, String>,
|
||||
val parent: TypeRemapper?,
|
||||
val isInlineLambda: Boolean = false
|
||||
) {
|
||||
private var additionalMappings: MutableMap<String, String> = hashMapOf()
|
||||
|
||||
|
||||
private val typeParametersMapping: MutableMap<String, TypeParameter> = hashMapOf()
|
||||
|
||||
fun addMapping(type: String, newType: String) {
|
||||
@@ -37,11 +38,11 @@ class TypeRemapper private constructor(private val typeMapping: MutableMap<Strin
|
||||
}
|
||||
|
||||
fun map(type: String): String {
|
||||
return typeMapping[type] ?: additionalMappings?.get(type) ?: type
|
||||
return typeMapping[type] ?: additionalMappings[type] ?: type
|
||||
}
|
||||
|
||||
fun addAdditionalMappings(oldName: String, newName: String) {
|
||||
additionalMappings!!.put(oldName, newName)
|
||||
additionalMappings[oldName] = newName
|
||||
}
|
||||
|
||||
fun registerTypeParameter(name: String) {
|
||||
@@ -52,7 +53,9 @@ class TypeRemapper private constructor(private val typeMapping: MutableMap<Strin
|
||||
}
|
||||
|
||||
fun registerTypeParameter(mapping: TypeParameterMapping) {
|
||||
typeParametersMapping[mapping.name] = TypeParameter(mapping.name, mapping.reificationArgument?.parameterName, mapping.isReified, mapping.signature)
|
||||
typeParametersMapping[mapping.name] = TypeParameter(
|
||||
mapping.name, mapping.reificationArgument?.parameterName, mapping.isReified, mapping.signature
|
||||
)
|
||||
}
|
||||
|
||||
fun mapTypeParameter(name: String): TypeParameter? {
|
||||
@@ -60,14 +63,13 @@ class TypeRemapper private constructor(private val typeMapping: MutableMap<Strin
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun createRoot(formalTypeParameters: TypeParameterMappings?): TypeRemapper {
|
||||
val typeRemapper = TypeRemapper(HashMap<String, String>(), null)
|
||||
formalTypeParameters?.forEach {
|
||||
typeRemapper.registerTypeParameter(it)
|
||||
return TypeRemapper(HashMap<String, String>(), null).apply {
|
||||
formalTypeParameters?.forEach {
|
||||
registerTypeParameter(it)
|
||||
}
|
||||
}
|
||||
return typeRemapper
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -82,9 +84,9 @@ class TypeRemapper private constructor(private val typeMapping: MutableMap<Strin
|
||||
}
|
||||
|
||||
private fun createNewAndMerge(remapper: TypeRemapper, additionalTypeMappings: Map<String, String>): MutableMap<String, String> {
|
||||
val map = HashMap(remapper.typeMapping)
|
||||
map += additionalTypeMappings
|
||||
return map
|
||||
return HashMap(remapper.typeMapping).apply {
|
||||
this += additionalTypeMappings
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user