Skip to content

Commit

Permalink
Fixed a hack which caused lambdas in interfaces to be backported twice
Browse files Browse the repository at this point in the history
Relates to issue #48
  • Loading branch information
luontola committed Apr 8, 2015
1 parent ead4b75 commit f0ad5a8
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 12 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ Version History

### Upcoming

- Fixed a hack which caused lambdas in interfaces to be backported twice,
possibly producing broken method calls in the bytecode
([Issue #48](https://github.com/orfjackal/retrolambda/issues/48))
- Removes generic method signatures from the default method implementation
methods which are placed in the interface's companion class, to avoid
them getting out of sync with their erased method descriptors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ protected void visit(byte[] bytecode) {

List<byte[]> transformed = new ArrayList<>();
for (ClassInfo c : interfaces) {
transformed.add(transformers.extractInterfaceCompanion(c.reader));
transformed.add(transformers.backportInterface(c.reader));
transformed.addAll(transformers.backportInterface(c.reader));
}
for (ClassInfo c : classes) {
transformed.add(transformers.backportClass(c.reader));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import net.orfjackal.retrolambda.trywithresources.SwallowSuppressedExceptions;
import org.objectweb.asm.*;

import java.util.Optional;
import java.util.*;

public class Transformers {

Expand Down Expand Up @@ -51,7 +51,22 @@ public byte[] backportClass(ClassReader reader) {
});
}

public byte[] backportInterface(ClassReader reader) {
public List<byte[]> backportInterface(ClassReader reader) {
// The lambdas must be backported only once, because bad things will happen if a lambda
// is called by different class name in the interface and its companion class, and then
// the wrong one of them is written to disk last.
byte[] lambdasBackported = transform(reader, (next) -> {
next = new BackportLambdaInvocations(next);
return next;
});

List<byte[]> results = new ArrayList<>();
results.add(backportInterface2(new ClassReader(lambdasBackported)));
results.addAll(extractInterfaceCompanion(new ClassReader(lambdasBackported)));
return results;
}

private byte[] backportInterface2(ClassReader reader) {
return transform(reader, (next) -> {
if (defaultMethodsEnabled) {
next = new RemoveStaticMethods(next);
Expand All @@ -65,24 +80,20 @@ public byte[] backportInterface(ClassReader reader) {
next = new WarnAboutDefaultAndStaticMethods(next);
}
next = new RemoveBridgeMethods(next);
next = new BackportLambdaInvocations(next);
return next;
});
}

public byte[] extractInterfaceCompanion(ClassReader reader) {
private List<byte[]> extractInterfaceCompanion(ClassReader reader) {
Optional<Type> companion = analyzer.getCompanionClass(Type.getObjectType(reader.getClassName()));
if (!companion.isPresent()) {
return null;
return Collections.emptyList();
}
return transform(reader, (next) -> {
return Arrays.asList(transform(reader, (next) -> {
next = new UpdateRelocatedMethodInvocations(next, analyzer);
next = new ExtractInterfaceCompanionClass(next, companion.get());
// XXX: We call BackportLambdaInvocations twice on the same interface (in backportInterface and extractInterfaceCompanion)
// - is this a problem, because it tries to load the lambda class twice?
next = new BackportLambdaInvocations(next);
return next;
});
}));
}

private byte[] transform(ClassReader reader, ClassVisitorChain chain) {
Expand Down

0 comments on commit f0ad5a8

Please sign in to comment.