Support anonymous object constructor transformation and inline
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.codegen.inline;
|
package org.jetbrains.jet.codegen.inline;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,6 +26,8 @@ public class ConstructorInvocation {
|
|||||||
|
|
||||||
private final String ownerInternalName;
|
private final String ownerInternalName;
|
||||||
|
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
private final Map<Integer, LambdaInfo> lambdasToInline;
|
private final Map<Integer, LambdaInfo> lambdasToInline;
|
||||||
|
|
||||||
private final boolean isSameModule;
|
private final boolean isSameModule;
|
||||||
@@ -37,15 +40,17 @@ public class ConstructorInvocation {
|
|||||||
|
|
||||||
private Map<String, LambdaInfo> capturedLambdasToInline;
|
private Map<String, LambdaInfo> capturedLambdasToInline;
|
||||||
|
|
||||||
private boolean capturedOuterRegenerated;
|
private final boolean capturedOuterRegenerated;
|
||||||
|
|
||||||
ConstructorInvocation(
|
ConstructorInvocation(
|
||||||
String ownerInternalName,
|
@NotNull String ownerInternalName,
|
||||||
Map<Integer, LambdaInfo> lambdasToInline,
|
@NotNull String desc,
|
||||||
|
@NotNull Map<Integer, LambdaInfo> lambdasToInline,
|
||||||
boolean isSameModule,
|
boolean isSameModule,
|
||||||
boolean capturedOuterRegenerated
|
boolean capturedOuterRegenerated
|
||||||
) {
|
) {
|
||||||
this.ownerInternalName = ownerInternalName;
|
this.ownerInternalName = ownerInternalName;
|
||||||
|
this.desc = desc;
|
||||||
this.lambdasToInline = lambdasToInline;
|
this.lambdasToInline = lambdasToInline;
|
||||||
this.isSameModule = isSameModule;
|
this.isSameModule = isSameModule;
|
||||||
this.capturedOuterRegenerated = capturedOuterRegenerated;
|
this.capturedOuterRegenerated = capturedOuterRegenerated;
|
||||||
@@ -95,4 +100,7 @@ public class ConstructorInvocation {
|
|||||||
this.capturedLambdasToInline = capturedLambdasToInline;
|
this.capturedLambdasToInline = capturedLambdasToInline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDesc() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,22 @@ package org.jetbrains.jet.codegen.inline;
|
|||||||
|
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.util.ArrayUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.OutputFile;
|
import org.jetbrains.jet.OutputFile;
|
||||||
import org.jetbrains.jet.codegen.*;
|
import org.jetbrains.jet.codegen.AsmUtil;
|
||||||
|
import org.jetbrains.jet.codegen.ClassBuilder;
|
||||||
|
import org.jetbrains.jet.codegen.FieldInfo;
|
||||||
|
import org.jetbrains.jet.codegen.StackValue;
|
||||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.org.objectweb.asm.*;
|
import org.jetbrains.org.objectweb.asm.*;
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
import org.jetbrains.org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.V1_6;
|
|
||||||
|
|
||||||
public class LambdaTransformer {
|
public class LambdaTransformer {
|
||||||
|
|
||||||
protected final GenerationState state;
|
protected final GenerationState state;
|
||||||
@@ -48,8 +50,6 @@ public class LambdaTransformer {
|
|||||||
|
|
||||||
private final ClassReader reader;
|
private final ClassReader reader;
|
||||||
|
|
||||||
private String superName;
|
|
||||||
|
|
||||||
private final boolean isSameModule;
|
private final boolean isSameModule;
|
||||||
|
|
||||||
private final Map<String, List<String>> fieldNames = new HashMap<String, List<String>>();
|
private final Map<String, List<String>> fieldNames = new HashMap<String, List<String>>();
|
||||||
@@ -91,28 +91,13 @@ public class LambdaTransformer {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public InlineResult doTransform(@NotNull ConstructorInvocation invocation, @NotNull FieldRemapper parentRemapper) {
|
public InlineResult doTransform(@NotNull ConstructorInvocation invocation, @NotNull FieldRemapper parentRemapper) {
|
||||||
final ClassBuilder classBuilder = createClassBuilder();
|
ClassBuilder classBuilder = createClassBuilder();
|
||||||
final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();
|
final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();
|
||||||
final List<FieldNode> fieldToAdd = new ArrayList<FieldNode>();
|
|
||||||
reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
|
reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
|
||||||
//TODO: public visibility for inline function
|
|
||||||
LambdaTransformer.this.superName = superName;
|
|
||||||
classBuilder.defineClass(null,
|
|
||||||
V1_6,
|
|
||||||
access,
|
|
||||||
newLambdaType.getInternalName(),
|
|
||||||
signature,
|
|
||||||
superName,
|
|
||||||
interfaces
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodVisitor visitMethod(
|
public MethodVisitor visitMethod(
|
||||||
int access, String name, 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>")){
|
||||||
@@ -128,26 +113,32 @@ public class LambdaTransformer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldVisitor visitField(
|
public FieldVisitor visitField(
|
||||||
int access, String name, String desc, String signature, Object value
|
int access, @NotNull String name, @NotNull String desc, String signature, Object value
|
||||||
) {
|
) {
|
||||||
addUniqueField(name);
|
addUniqueField(name);
|
||||||
FieldNode fieldNode = new FieldNode(access, name, desc, signature, value);
|
if (InlineCodegenUtil.isCapturedFieldName(name)) {
|
||||||
fieldToAdd.add(fieldNode);
|
return null;
|
||||||
return fieldNode;
|
} else {
|
||||||
|
return super.visitField(access, name, desc, signature, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, ClassReader.SKIP_FRAMES);
|
}, ClassReader.SKIP_FRAMES);
|
||||||
|
|
||||||
ParametersBuilder capturedBuilder = ParametersBuilder.newBuilder();
|
ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
|
||||||
extractParametersMappingAndPatchConstructor(constructor, capturedBuilder, invocation);
|
ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder();
|
||||||
|
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, invocation);
|
||||||
|
|
||||||
InlineResult result = InlineResult.create();
|
InlineResult result = InlineResult.create();
|
||||||
for (MethodNode next : methodsToTransform) {
|
for (MethodNode next : methodsToTransform) {
|
||||||
MethodVisitor visitor = newMethod(classBuilder, next);
|
MethodVisitor visitor = newMethod(classBuilder, next);
|
||||||
InlineResult funResult = inlineMethod(invocation, parentRemapper, visitor, next, capturedBuilder);
|
InlineResult funResult = inlineMethod(invocation, parentRemapper, visitor, next, allCapturedParamBuilder);
|
||||||
result.addAllClassesToRemove(funResult);
|
result.addAllClassesToRemove(funResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
generateConstructorAndFields(classBuilder, capturedBuilder, invocation);
|
InlineResult constructorResult =
|
||||||
|
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, invocation, parentRemapper);
|
||||||
|
|
||||||
|
result.addAllClassesToRemove(constructorResult);
|
||||||
|
|
||||||
classBuilder.done();
|
classBuilder.done();
|
||||||
|
|
||||||
@@ -178,22 +169,82 @@ public class LambdaTransformer {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateConstructorAndFields(@NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder builder, @NotNull ConstructorInvocation invocation) {
|
private InlineResult generateConstructorAndFields(
|
||||||
List<CapturedParamInfo> infos = builder.buildCaptured();
|
@NotNull ClassBuilder classBuilder,
|
||||||
List<Pair<String, Type>> newConstructorSignature = new ArrayList<Pair<String, Type>>();
|
@NotNull ParametersBuilder allCapturedBuilder,
|
||||||
for (CapturedParamInfo capturedParamInfo : infos) {
|
@NotNull ParametersBuilder constructorInlineBuilder,
|
||||||
if (capturedParamInfo.getLambda() == null) { //not inlined
|
@NotNull ConstructorInvocation invocation,
|
||||||
newConstructorSignature.add(new Pair<String, Type>(capturedParamInfo.getNewFieldName(), capturedParamInfo.getType()));
|
@NotNull FieldRemapper parentRemapper
|
||||||
|
) {
|
||||||
|
List<Type> descTypes = new ArrayList<Type>();
|
||||||
|
|
||||||
|
Parameters constructorParams = constructorInlineBuilder.buildParameters();
|
||||||
|
final int [] capturedIndexes = new int [constructorParams.totalSize()];
|
||||||
|
int index = 0;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
//complex processing cause it could have super constructor call params
|
||||||
|
for (ParameterInfo info : constructorParams) {
|
||||||
|
if (!info.isSkipped()) { //not inlined
|
||||||
|
if (info.isCaptured() || info instanceof CapturedParamInfo) {
|
||||||
|
capturedIndexes[index] = size;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size != 0) { //skip this
|
||||||
|
descTypes.add(info.getType());
|
||||||
|
}
|
||||||
|
size += info.getType().getSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FieldInfo> fields = AsmUtil.transformCapturedParams(newConstructorSignature, newLambdaType);
|
final List<Pair<String, Type>> capturedFieldsToGenerate = new ArrayList<Pair<String, Type>>();
|
||||||
|
for (CapturedParamInfo capturedParamInfo : allCapturedBuilder.listCaptured()) {
|
||||||
|
if (capturedParamInfo.getLambda() == null) { //not inlined
|
||||||
|
capturedFieldsToGenerate.add(new Pair<String, Type>(capturedParamInfo.getNewFieldName(), capturedParamInfo.getType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AsmUtil.genClosureFields(newConstructorSignature, classBuilder);
|
String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()]));
|
||||||
|
|
||||||
|
MethodVisitor constructorVisitor = classBuilder.newMethod(null,
|
||||||
|
AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
|
||||||
|
"<init>", constructorDescriptor,
|
||||||
|
null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||||
|
|
||||||
|
MethodVisitor capturedFieldInitializer = new InstructionAdapter(InlineCodegenUtil.API, constructorVisitor) {
|
||||||
|
private boolean superCallProcessed;
|
||||||
|
@Override
|
||||||
|
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||||
|
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||||
|
if (!superCallProcessed && "<init>".equals(name)) {
|
||||||
|
superCallProcessed = true;
|
||||||
|
List<FieldInfo> fields = AsmUtil.transformCapturedParams(capturedFieldsToGenerate, newLambdaType);
|
||||||
|
int paramIndex = 0;
|
||||||
|
for (FieldInfo fieldInfo : fields) {
|
||||||
|
AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], this);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Parameters constructorParameters = constructorInlineBuilder.buildParameters();
|
||||||
|
|
||||||
|
RegeneratedLambdaFieldRemapper remapper =
|
||||||
|
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(),
|
||||||
|
constructorParameters, invocation.getCapturedLambdasToInline(),
|
||||||
|
parentRemapper);
|
||||||
|
|
||||||
|
MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
|
||||||
|
remapper, isSameModule, "Transformer for constructor of " + invocation.getOwnerInternalName());
|
||||||
|
InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false);
|
||||||
|
constructorVisitor.visitMaxs(-1, -1);
|
||||||
|
|
||||||
|
AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder);
|
||||||
//TODO for inline method make public class
|
//TODO for inline method make public class
|
||||||
Method newConstructor = ClosureCodegen.generateConstructor(classBuilder, fields, null, Type.getObjectType(superName), state, AsmUtil.NO_FLAG_PACKAGE_PRIVATE);
|
invocation.setNewConstructorDescriptor(constructorDescriptor);
|
||||||
invocation.setNewConstructorDescriptor(newConstructor.getDescriptor());
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -203,7 +254,7 @@ public class LambdaTransformer {
|
|||||||
) {
|
) {
|
||||||
ParametersBuilder builder = ParametersBuilder.newBuilder();
|
ParametersBuilder builder = ParametersBuilder.newBuilder();
|
||||||
buildInvokeParamsFor(builder, sourceNode);
|
buildInvokeParamsFor(builder, sourceNode);
|
||||||
for (CapturedParamInfo param : capturedBuilder.getCapturedParams()) {
|
for (CapturedParamInfo param : capturedBuilder.listCaptured()) {
|
||||||
builder.addCapturedParamCopy(param);
|
builder.addCapturedParamCopy(param);
|
||||||
}
|
}
|
||||||
return builder.buildParameters();
|
return builder.buildParameters();
|
||||||
@@ -229,11 +280,11 @@ public class LambdaTransformer {
|
|||||||
|
|
||||||
private void extractParametersMappingAndPatchConstructor(
|
private void extractParametersMappingAndPatchConstructor(
|
||||||
@NotNull MethodNode constructor,
|
@NotNull MethodNode constructor,
|
||||||
@NotNull ParametersBuilder builder,
|
@NotNull ParametersBuilder capturedParamBuilder,
|
||||||
|
@NotNull ParametersBuilder constructorParamBuilder,
|
||||||
@NotNull final ConstructorInvocation invocation
|
@NotNull final ConstructorInvocation invocation
|
||||||
) {
|
) {
|
||||||
Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
|
|
||||||
List<LambdaInfo> capturedLambdas = new ArrayList<LambdaInfo>(); //captured var of inlined parameter
|
|
||||||
CapturedParamOwner owner = new CapturedParamOwner() {
|
CapturedParamOwner owner = new CapturedParamOwner() {
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
@@ -241,24 +292,41 @@ public class LambdaTransformer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractInsnNode cur = constructor.instructions.getFirst();
|
List<LambdaInfo> capturedLambdas = new ArrayList<LambdaInfo>(); //captured var of inlined parameter
|
||||||
//load captured parameters (NB: there is also could be object fields)
|
List<CapturedParamInfo> capturedToInline = new ArrayList<CapturedParamInfo>();
|
||||||
while (cur != null) {
|
Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
|
||||||
if (cur instanceof FieldInsnNode && cur.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(((FieldInsnNode) cur).name)) {
|
Set<Integer> capturedParams = new HashSet<Integer>();
|
||||||
FieldInsnNode fieldNode = (FieldInsnNode) cur;
|
|
||||||
CapturedParamInfo info = builder.addCapturedParam(owner, fieldNode.name, Type.getType(fieldNode.desc), false, null);
|
|
||||||
|
|
||||||
boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
|
//load captured parameters and patch instruction list (NB: there is also could be object fields)
|
||||||
boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;
|
AbstractInsnNode cur = constructor.instructions.getFirst();
|
||||||
if (isPrevPrevVarNode) {
|
while (cur != null) {
|
||||||
VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious();
|
if (cur instanceof FieldInsnNode) {
|
||||||
if (node.var == 0) {
|
FieldInsnNode fieldNode = (FieldInsnNode) cur;
|
||||||
VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
|
if (fieldNode.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldNode.name)) {
|
||||||
int varIndex = previous.var;
|
|
||||||
LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
|
boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
|
||||||
if (lambdaInfo != null) {
|
boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;
|
||||||
info.setLambda(lambdaInfo);
|
|
||||||
capturedLambdas.add(lambdaInfo);
|
if (isPrevPrevVarNode) {
|
||||||
|
VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious();
|
||||||
|
if (node.var == 0) {
|
||||||
|
VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
|
||||||
|
int varIndex = previous.var;
|
||||||
|
LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
|
||||||
|
CapturedParamInfo info = capturedParamBuilder.addCapturedParam(owner, fieldNode.name, Type.getType(fieldNode.desc), lambdaInfo != null, null);
|
||||||
|
if (lambdaInfo != null) {
|
||||||
|
info.setLambda(lambdaInfo);
|
||||||
|
capturedLambdas.add(lambdaInfo);
|
||||||
|
capturedToInline.add(info);
|
||||||
|
}
|
||||||
|
capturedParams.add(varIndex);
|
||||||
|
|
||||||
|
constructor.instructions.remove(previous.getPrevious());
|
||||||
|
constructor.instructions.remove(previous);
|
||||||
|
AbstractInsnNode temp = cur;
|
||||||
|
cur = cur.getNext();
|
||||||
|
constructor.instructions.remove(temp);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,13 +334,27 @@ public class LambdaTransformer {
|
|||||||
cur = cur.getNext();
|
cur = cur.getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructorParamBuilder.addThis(oldObjectType, false);
|
||||||
|
Type [] types = Type.getArgumentTypes(invocation.getDesc());
|
||||||
|
for (Type type : types) {
|
||||||
|
LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex());
|
||||||
|
ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null, null);
|
||||||
|
parameterInfo.setLambda(info);
|
||||||
|
if (capturedParams.contains(parameterInfo.getIndex())) {
|
||||||
|
parameterInfo.setCaptured(true);
|
||||||
|
} else {
|
||||||
|
//otherwise it's super constructor parameter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//For all inlined lambdas add their captured parameters
|
//For all inlined lambdas add their captured parameters
|
||||||
//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<CapturedParamInfo> allRecapturedParameters = new ArrayList<CapturedParamInfo>();
|
List<CapturedParamInfo> allRecapturedParameters = new ArrayList<CapturedParamInfo>();
|
||||||
for (LambdaInfo info : capturedLambdas) {
|
for (LambdaInfo info : capturedLambdas) {
|
||||||
for (CapturedParamInfo var : info.getCapturedVars()) {
|
for (CapturedParamInfo var : info.getCapturedVars()) {
|
||||||
CapturedParamInfo recapturedParamInfo = builder.addCapturedParam(var, getNewFieldName(var.getOriginalFieldName()));
|
CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(var,
|
||||||
|
getNewFieldName(var.getOriginalFieldName()));
|
||||||
StackValue composed = StackValue.composed(StackValue.local(0, oldObjectType),
|
StackValue composed = StackValue.composed(StackValue.local(0, oldObjectType),
|
||||||
StackValue.field(var.getType(),
|
StackValue.field(var.getType(),
|
||||||
oldObjectType, /*TODO owner type*/
|
oldObjectType, /*TODO owner type*/
|
||||||
@@ -280,10 +362,18 @@ public class LambdaTransformer {
|
|||||||
);
|
);
|
||||||
recapturedParamInfo.setRemapValue(composed);
|
recapturedParamInfo.setRemapValue(composed);
|
||||||
allRecapturedParameters.add(var);
|
allRecapturedParameters.add(var);
|
||||||
|
|
||||||
|
constructorParamBuilder.addCapturedParam(var, recapturedParamInfo.getNewFieldName()).setRemapValue(composed);
|
||||||
}
|
}
|
||||||
capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info);
|
capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//HACK: in inlinining into constructor we access inlined lambda with field access not local var but this lambda added no general params not captured one,
|
||||||
|
//so we need to add them to captured params
|
||||||
|
for (CapturedParamInfo info : capturedToInline) {
|
||||||
|
constructorParamBuilder.addCapturedParamCopy(info);
|
||||||
|
}
|
||||||
|
|
||||||
invocation.setAllRecapturedParameters(allRecapturedParameters);
|
invocation.setAllRecapturedParameters(allRecapturedParameters);
|
||||||
invocation.setCapturedLambdasToInline(capturedLambdasToInline);
|
invocation.setCapturedLambdasToInline(capturedLambdasToInline);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ public class MethodInliner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructorInvocations.add(new ConstructorInvocation(owner, lambdaMapping, isSameModule, inliningContext.classRegeneration));
|
constructorInvocations.add(new ConstructorInvocation(owner, desc, lambdaMapping, isSameModule, inliningContext.classRegeneration));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ class ParameterInfo {
|
|||||||
|
|
||||||
protected final int index;
|
protected final int index;
|
||||||
|
|
||||||
|
private boolean isCaptured;
|
||||||
|
|
||||||
public final Type type;
|
public final Type type;
|
||||||
|
|
||||||
//for skipped parameter: e.g. inlined lambda
|
//for skipped parameter: e.g. inlined lambda
|
||||||
@@ -87,4 +89,12 @@ class ParameterInfo {
|
|||||||
public void setRemapValue(StackValue remapValue) {
|
public void setRemapValue(StackValue remapValue) {
|
||||||
this.remapValue = remapValue;
|
this.remapValue = remapValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCaptured() {
|
||||||
|
return isCaptured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaptured(boolean isCaptured) {
|
||||||
|
this.isCaptured = isCaptured;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,10 +88,10 @@ public class Parameters implements Iterable<ParameterInfo> {
|
|||||||
ArrayList<Type> result = new ArrayList<Type>();
|
ArrayList<Type> result = new ArrayList<Type>();
|
||||||
for (CapturedParamInfo info : captured) {
|
for (CapturedParamInfo info : captured) {
|
||||||
if(info != CapturedParamInfo.STUB) {
|
if(info != CapturedParamInfo.STUB) {
|
||||||
Type type = info.getType();
|
result.add(info.getType());
|
||||||
result.add(type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,8 @@ public class ParametersBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ParametersBuilder addNextParameter(@NotNull Type type, boolean skipped, @Nullable ParameterInfo original) {
|
public ParameterInfo addNextParameter(@NotNull Type type, boolean skipped, @Nullable ParameterInfo original) {
|
||||||
addParameter(new ParameterInfo(type, skipped, nextIndex, original != null ? original.getIndex() : -1));
|
return addParameter(new ParameterInfo(type, skipped, nextIndex, original != null ? original.getIndex() : -1));
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -83,9 +82,10 @@ public class ParametersBuilder {
|
|||||||
return addCapturedParameter(info);
|
return addCapturedParameter(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addParameter(ParameterInfo info) {
|
private ParameterInfo addParameter(ParameterInfo info) {
|
||||||
params.add(info);
|
params.add(info);
|
||||||
nextIndex += info.getType().getSize();
|
nextIndex += info.getType().getSize();
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CapturedParamInfo addCapturedParameter(CapturedParamInfo info) {
|
private CapturedParamInfo addCapturedParameter(CapturedParamInfo info) {
|
||||||
@@ -94,27 +94,30 @@ public class ParametersBuilder {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ParameterInfo> build() {
|
@NotNull
|
||||||
|
public List<ParameterInfo> listNotCaptured() {
|
||||||
return Collections.unmodifiableList(params);
|
return Collections.unmodifiableList(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CapturedParamInfo> buildCaptured() {
|
@NotNull
|
||||||
|
public List<CapturedParamInfo> listCaptured() {
|
||||||
return Collections.unmodifiableList(capturedParams);
|
return Collections.unmodifiableList(capturedParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ParameterInfo> buildWithStubs() {
|
@NotNull
|
||||||
return Parameters.addStubs(build());
|
private List<ParameterInfo> buildWithStubs() {
|
||||||
|
return Parameters.addStubs(listNotCaptured());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CapturedParamInfo> buildCapturedWithStubs() {
|
private List<CapturedParamInfo> buildCapturedWithStubs() {
|
||||||
return Parameters.shiftAndAddStubs(buildCaptured(), nextIndex);
|
return Parameters.shiftAndAddStubs(listCaptured(), nextIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Parameters buildParameters() {
|
public Parameters buildParameters() {
|
||||||
return new Parameters(buildWithStubs(), buildCapturedWithStubs());
|
return new Parameters(buildWithStubs(), buildCapturedWithStubs());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CapturedParamInfo> getCapturedParams() {
|
public int getNextValueParameterIndex() {
|
||||||
return capturedParams;
|
return nextIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun test1(): String {
|
||||||
|
val o = "O"
|
||||||
|
|
||||||
|
val result = doWork ({o}, {"K"})
|
||||||
|
|
||||||
|
return result.getO() + result.getK()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() : String {
|
||||||
|
//same names as in object
|
||||||
|
val o1 = "O"
|
||||||
|
val k1 = "K"
|
||||||
|
|
||||||
|
val result = doWorkInConstructor ({o1}, {k1})
|
||||||
|
|
||||||
|
return result.getO() + result.getK()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
val result1 = test1();
|
||||||
|
if (result1 != "OK") return "fail1 $result1"
|
||||||
|
|
||||||
|
val result2 = test2();
|
||||||
|
if (result2 != "OK") return "fail2 $result2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
abstract class A<R> {
|
||||||
|
abstract fun getO() : R
|
||||||
|
|
||||||
|
abstract fun getK() : R
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <R> doWork(jobO: ()-> R, jobK: ()-> R) : A<R> {
|
||||||
|
val s = object : A<R>() {
|
||||||
|
|
||||||
|
override fun getO(): R {
|
||||||
|
return jobO()
|
||||||
|
}
|
||||||
|
override fun getK(): R {
|
||||||
|
return jobK()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <R> doWorkInConstructor(jobO: ()-> R, jobK: ()-> R) : A<R> {
|
||||||
|
val s = object : A<R>() {
|
||||||
|
val o1 = jobO()
|
||||||
|
|
||||||
|
val k1 = jobK()
|
||||||
|
|
||||||
|
override fun getO(): R {
|
||||||
|
return o1
|
||||||
|
}
|
||||||
|
override fun getK(): R {
|
||||||
|
return k1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun test1(): String {
|
||||||
|
val o = "O"
|
||||||
|
|
||||||
|
val result = doWork ({o}, {"K"}, "11")
|
||||||
|
|
||||||
|
return result.getO() + result.getK() + result.param
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() : String {
|
||||||
|
//same names as in object
|
||||||
|
val o1 = "O"
|
||||||
|
val k1 = "K"
|
||||||
|
val param = "11"
|
||||||
|
val result = doWorkInConstructor ({o1}, {k1}, {param})
|
||||||
|
|
||||||
|
return result.getO() + result.getK() + result.param
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
val result1 = test1();
|
||||||
|
if (result1 != "OK11") return "fail1 $result1"
|
||||||
|
|
||||||
|
val result2 = test2();
|
||||||
|
if (result2 != "OK11") return "fail2 $result2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
abstract class A<R>(val param : R) {
|
||||||
|
abstract fun getO() : R
|
||||||
|
|
||||||
|
abstract fun getK() : R
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <R> doWork(jobO: ()-> R, jobK: ()-> R, param: R) : A<R> {
|
||||||
|
val s = object : A<R>(param) {
|
||||||
|
|
||||||
|
override fun getO(): R {
|
||||||
|
return jobO()
|
||||||
|
}
|
||||||
|
override fun getK(): R {
|
||||||
|
return jobK()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <R> doWorkInConstructor(jobO: ()-> R, jobK: ()-> R, param: () -> R) : A<R> {
|
||||||
|
val s = object : A<R>(param()) {
|
||||||
|
val o1 = jobO()
|
||||||
|
|
||||||
|
val k1 = jobK()
|
||||||
|
|
||||||
|
override fun getO(): R {
|
||||||
|
return o1
|
||||||
|
}
|
||||||
|
override fun getK(): R {
|
||||||
|
return k1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
+13
-3
@@ -41,9 +41,19 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT
|
|||||||
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite");
|
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("anonymousObjectSuperParams")
|
@TestMetadata("anonymousObjectOnCallSiteSuperParams")
|
||||||
public void testAnonymousObjectSuperParams() throws Exception {
|
public void testAnonymousObjectOnCallSiteSuperParams() throws Exception {
|
||||||
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectSuperParams");
|
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSiteSuperParams");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousObjectOnDeclarationSite")
|
||||||
|
public void testAnonymousObjectOnDeclarationSite() throws Exception {
|
||||||
|
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousObjectOnDeclarationSiteSuperParams")
|
||||||
|
public void testAnonymousObjectOnDeclarationSiteSuperParams() throws Exception {
|
||||||
|
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSiteSuperParams");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("builders")
|
@TestMetadata("builders")
|
||||||
|
|||||||
+13
-3
@@ -41,9 +41,19 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite");
|
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("anonymousObjectSuperParams")
|
@TestMetadata("anonymousObjectOnCallSiteSuperParams")
|
||||||
public void testAnonymousObjectSuperParams() throws Exception {
|
public void testAnonymousObjectOnCallSiteSuperParams() throws Exception {
|
||||||
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectSuperParams");
|
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSiteSuperParams");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousObjectOnDeclarationSite")
|
||||||
|
public void testAnonymousObjectOnDeclarationSite() throws Exception {
|
||||||
|
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousObjectOnDeclarationSiteSuperParams")
|
||||||
|
public void testAnonymousObjectOnDeclarationSiteSuperParams() throws Exception {
|
||||||
|
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSiteSuperParams");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("builders")
|
@TestMetadata("builders")
|
||||||
|
|||||||
Reference in New Issue
Block a user