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 String ownerInternalName;
private final Map<Integer, InvokeCall> access; private final Map<Integer, LambdaInfo> lambdasToInline;
private final boolean isSameModule; private final boolean isSameModule;
@@ -37,9 +37,9 @@ public class ConstructorInvocation {
private Map<String, LambdaInfo> recapturedLambdas; 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.ownerInternalName = ownerInternalName;
this.access = access; this.lambdasToInline = lambdasToInline;
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
} }
@@ -47,12 +47,12 @@ public class ConstructorInvocation {
return ownerInternalName; return ownerInternalName;
} }
public boolean isInlinable() { public boolean shouldRegenerate() {
return !access.isEmpty() || !isSameModule; return !lambdasToInline.isEmpty() || !isSameModule;
} }
public Map<Integer, InvokeCall> getAccess() { public Map<Integer, LambdaInfo> getLambdasToInline() {
return access; return lambdasToInline;
} }
@@ -189,7 +189,7 @@ public class LambdaTransformer {
} }
private void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) { 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(); AbstractInsnNode cur = constructor.instructions.getFirst();
cur = cur.getNext(); //skip super call cur = cur.getNext(); //skip super call
@@ -202,13 +202,10 @@ public class LambdaTransformer {
paramMapping.put(fieldNode.name, varIndex); paramMapping.put(fieldNode.name, varIndex);
CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null); CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null);
InvokeCall access = indexToLambda.get(varIndex); LambdaInfo LambdaInfo = indexToLambda.get(varIndex);
if (access != null) { if (LambdaInfo != null) {
LambdaInfo accessInfo = access.lambdaInfo; info.setLambda(LambdaInfo);
if (accessInfo != null) { additionalCaptured.add(LambdaInfo);
info.setLambda(accessInfo);
additionalCaptured.add(accessInfo);
}
} }
} }
cur = cur.getNext(); cur = cur.getNext();
@@ -119,19 +119,20 @@ public class MethodInliner {
if (isLambdaConstructorCall(type.getInternalName(), "<init>")) { if (isLambdaConstructorCall(type.getInternalName(), "<init>")) {
invocation = iterator.next(); invocation = iterator.next();
if (invocation.isInlinable()) { if (invocation.shouldRegenerate()) {
//TODO: need poping of type but what to do with local funs??? //TODO: need poping of type but what to do with local funs???
Type newLambdaType = Type.getObjectType(parent.nameGenerator.genLambdaClassName()); Type newLambdaType = Type.getObjectType(parent.nameGenerator.genLambdaClassName());
currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName()); 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); isSameModule, newLambdaType);
transformer.doTransform(invocation); 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 @Override
@@ -167,12 +168,11 @@ public class MethodInliner {
} }
else if (isLambdaConstructorCall(owner, name)) { //TODO add method else if (isLambdaConstructorCall(owner, name)) { //TODO add method
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name; assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
if (invocation.isInlinable()) { if (invocation.shouldRegenerate()) {
//put additional captured parameters on stack //put additional captured parameters on stack
List<CapturedParamInfo> recaptured = invocation.getRecaptured(); List<CapturedParamInfo> recaptured = invocation.getRecaptured();
List<CapturedParamInfo> contextCaptured = MethodInliner.this.parameters.getCaptured();
for (CapturedParamInfo capturedParamInfo : recaptured) { for (CapturedParamInfo capturedParamInfo : recaptured) {
Type type = capturedParamInfo.getType();
List<CapturedParamInfo> contextCaptured = MethodInliner.this.parameters.getCaptured();
CapturedParamInfo result = null; CapturedParamInfo result = null;
for (CapturedParamInfo info : contextCaptured) { for (CapturedParamInfo info : contextCaptured) {
//TODO more sophisticated check //TODO more sophisticated check
@@ -180,7 +180,12 @@ public class MethodInliner {
result = info; 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()); super.visitMethodInsn(opcode, invocation.getNewLambdaType().getInternalName(), name, invocation.getNewConstructorDescriptor());
invocation = null; invocation = null;
@@ -296,25 +301,25 @@ public class MethodInliner {
invokeCalls.add(new InvokeCall(varIndex, lambdaInfo)); invokeCalls.add(new InvokeCall(varIndex, lambdaInfo));
} }
else if (isLambdaConstructorCall(owner, name)) { 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; int paramStart = frame.getStackSize() - paramLength;
for (int i = 0; i < paramLength; i++) { for (int i = 0; i < paramLength; i++) {
SourceValue sourceValue = frame.getStack(paramStart + i); SourceValue sourceValue = frame.getStack(paramStart + i);
if (sourceValue.insns.size() == 1) { if (sourceValue.insns.size() == 1) {
AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); 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; int varIndex = ((VarInsnNode) insnNode).var;
LambdaInfo lambdaInfo = getLambda(varIndex); LambdaInfo lambdaInfo = getLambda(varIndex);
if (lambdaInfo != null) { if (lambdaInfo != null) {
infos.put(i, new InvokeCall(varIndex, lambdaInfo)); lambdaMapping.put(i, lambdaInfo);
node.instructions.remove(insnNode); 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) { public String changeOwnerForExternalPackage(String type, int opcode) {
if (isSameModule || (opcode & Opcodes.INVOKESTATIC) == 0) { if (isSameModule || (opcode & Opcodes.INVOKESTATIC) == 0) {
return type; return type;