Construction invocation simplification

This commit is contained in:
Mikhael Bogdanov
2014-02-26 17:05:11 +04:00
parent cd030ec88e
commit 2d2ffea807
3 changed files with 33 additions and 28 deletions
@@ -25,7 +25,7 @@ public class ConstructorInvocation {
private final String ownerInternalName;
private final Map<Integer, InvokeCall> access;
private final Map<Integer, LambdaInfo> lambdasToInline;
private final boolean isSameModule;
@@ -37,9 +37,9 @@ public class ConstructorInvocation {
private Map<String, LambdaInfo> recapturedLambdas;
ConstructorInvocation(String ownerInternalName, Map<Integer, InvokeCall> access, boolean isSameModule) {
ConstructorInvocation(String ownerInternalName, Map<Integer, LambdaInfo> lambdasToInline, boolean isSameModule) {
this.ownerInternalName = ownerInternalName;
this.access = access;
this.lambdasToInline = lambdasToInline;
this.isSameModule = isSameModule;
}
@@ -47,12 +47,12 @@ public class ConstructorInvocation {
return ownerInternalName;
}
public boolean isInlinable() {
return !access.isEmpty() || !isSameModule;
public boolean shouldRegenerate() {
return !lambdasToInline.isEmpty() || !isSameModule;
}
public Map<Integer, InvokeCall> getAccess() {
return access;
public Map<Integer, LambdaInfo> getLambdasToInline() {
return lambdasToInline;
}
@@ -189,7 +189,7 @@ public class LambdaTransformer {
}
private void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) {
Map<Integer, InvokeCall> indexToLambda = invocation.getAccess();
Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
AbstractInsnNode cur = constructor.instructions.getFirst();
cur = cur.getNext(); //skip super call
@@ -202,13 +202,10 @@ public class LambdaTransformer {
paramMapping.put(fieldNode.name, varIndex);
CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null);
InvokeCall access = indexToLambda.get(varIndex);
if (access != null) {
LambdaInfo accessInfo = access.lambdaInfo;
if (accessInfo != null) {
info.setLambda(accessInfo);
additionalCaptured.add(accessInfo);
}
LambdaInfo LambdaInfo = indexToLambda.get(varIndex);
if (LambdaInfo != null) {
info.setLambda(LambdaInfo);
additionalCaptured.add(LambdaInfo);
}
}
cur = cur.getNext();
@@ -119,19 +119,20 @@ public class MethodInliner {
if (isLambdaConstructorCall(type.getInternalName(), "<init>")) {
invocation = iterator.next();
if (invocation.isInlinable()) {
if (invocation.shouldRegenerate()) {
//TODO: need poping of type but what to do with local funs???
Type newLambdaType = Type.getObjectType(parent.nameGenerator.genLambdaClassName());
currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName());
LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(), parent.subInline(parent.nameGenerator, currentTypeMapping),
LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(),
parent.subInline(parent.nameGenerator, currentTypeMapping),
isSameModule, newLambdaType);
transformer.doTransform(invocation);
}
super.anew(type);
} else {
super.anew(type);
}
//in case of regenerated invocation type would be remapped to new one via remappingMethodAdapter
super.anew(type);
}
@Override
@@ -167,12 +168,11 @@ public class MethodInliner {
}
else if (isLambdaConstructorCall(owner, name)) { //TODO add method
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
if (invocation.isInlinable()) {
if (invocation.shouldRegenerate()) {
//put additional captured parameters on stack
List<CapturedParamInfo> recaptured = invocation.getRecaptured();
List<CapturedParamInfo> contextCaptured = MethodInliner.this.parameters.getCaptured();
for (CapturedParamInfo capturedParamInfo : recaptured) {
Type type = capturedParamInfo.getType();
List<CapturedParamInfo> contextCaptured = MethodInliner.this.parameters.getCaptured();
CapturedParamInfo result = null;
for (CapturedParamInfo info : contextCaptured) {
//TODO more sophisticated check
@@ -180,7 +180,12 @@ public class MethodInliner {
result = info;
}
}
super.visitVarInsn(type.getOpcode(Opcodes.ILOAD), result.getIndex());
if (result == null) {
throw new UnsupportedOperationException(
"Unsupported operation: could not transform non-inline lambda inside inlined one: " +
owner + "." + name);
}
super.visitVarInsn(capturedParamInfo.getType().getOpcode(Opcodes.ILOAD), result.getIndex());
}
super.visitMethodInsn(opcode, invocation.getNewLambdaType().getInternalName(), name, invocation.getNewConstructorDescriptor());
invocation = null;
@@ -296,25 +301,25 @@ public class MethodInliner {
invokeCalls.add(new InvokeCall(varIndex, lambdaInfo));
}
else if (isLambdaConstructorCall(owner, name)) {
Map<Integer, InvokeCall> infos = new HashMap<Integer, InvokeCall>();
Map<Integer, LambdaInfo> lambdaMapping = new HashMap<Integer, LambdaInfo>();
int paramStart = frame.getStackSize() - paramLength;
for (int i = 0; i < paramLength; i++) {
SourceValue sourceValue = frame.getStack(paramStart + i);
if (sourceValue.insns.size() == 1) {
AbstractInsnNode insnNode = sourceValue.insns.iterator().next();
if (insnNode.getType() == AbstractInsnNode.VAR_INSN && insnNode.getOpcode() == Opcodes.ALOAD) {
if (insnNode.getOpcode() == Opcodes.ALOAD) {
int varIndex = ((VarInsnNode) insnNode).var;
LambdaInfo lambdaInfo = getLambda(varIndex);
if (lambdaInfo != null) {
infos.put(i, new InvokeCall(varIndex, lambdaInfo));
lambdaMapping.put(i, lambdaInfo);
node.instructions.remove(insnNode);
}
}
}
}
constructorInvocations.add(new ConstructorInvocation(owner, infos, isSameModule));
constructorInvocations.add(new ConstructorInvocation(owner, lambdaMapping, isSameModule));
}
}
}
@@ -456,6 +461,9 @@ public class MethodInliner {
}
}
//TODO: check annotation on class - it's package part
//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;