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