Skip to content

Don't process default methods at all #162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public class ClassAnalyzer {
private final Map<MethodRef, MethodRef> relocatedMethods = new HashMap<>();
private final Map<MethodRef, MethodRef> renamedLambdaMethods = new HashMap<>();

protected String companionClassName(String name) {
return name + "$";
}

public void analyze(byte[] bytecode, boolean isJavacHacksEnabled) {
analyze(EnhancedClassReader.create(bytecode, isJavacHacksEnabled));
}
Expand Down Expand Up @@ -68,12 +72,14 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
private void analyzeInterface(ClassInfo c, ClassReader cr) {
cr.accept(new ClassVisitor(ASM5) {
private String owner;
private String companion;

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.owner = name;
this.companion = name + "$";
}

private String companionName() {
return companionClassName(owner);
}

@Override
Expand All @@ -84,17 +90,19 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
c.addMethod(access, method, new MethodKind.Abstract());

} else if (isDefaultMethod(access)) {
String companion = companionName();
MethodRef defaultImpl = new MethodRef(H_INVOKESTATIC, companion, name, Bytecode.prependArgumentType(desc, Type.getObjectType(owner)));
c.enableCompanionClass();
c.enableCompanionClass(companion);
c.addMethod(access, method, new MethodKind.Default(defaultImpl));

} else if (isInstanceLambdaImplMethod(access)) {
String companion = companionName();
relocatedMethods.put(method, new MethodRef(H_INVOKESTATIC, companion, name, Bytecode.prependArgumentType(desc, Type.getObjectType(owner))));
c.enableCompanionClass();

c.enableCompanionClass(companion);
} else if (isStaticMethod(access) && !isStaticInitializer(name, desc, access)) {
String companion = companionName();
relocatedMethods.put(method, new MethodRef(H_INVOKESTATIC, companion, name, desc));
c.enableCompanionClass();
c.enableCompanionClass(companion);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public Optional<Type> getCompanionClass() {
return companionClass;
}

public void enableCompanionClass() {
this.companionClass = Optional.of(Type.getObjectType(type.getInternalName() + "$"));
public void enableCompanionClass(String name) {
this.companionClass = Optional.of(Type.getObjectType(name));
}

public boolean isClass() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ private static CallSite callBootstrapMethod(Class<?> invoker, String invokedName
}

private static MethodHandles.Lookup getLookup(Class<?> targetClass) throws Exception {
Constructor<MethodHandles.Lookup> ctor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);
Constructor<MethodHandles.Lookup> ctor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
ctor.setAccessible(true);
return ctor.newInstance(targetClass);
return ctor.newInstance(targetClass, 0x1f);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ private static Class<?> toClass(Type type, ClassLoader classLoader) throws Class

public static MethodHandle toMethodHandle(Handle handle, ClassLoader classLoader, MethodHandles.Lookup lookup) throws Exception {
MethodType type = MethodType.fromMethodDescriptorString(handle.getDesc(), classLoader);
Class<?> owner = classLoader.loadClass(handle.getOwner().replace('/', '.'));

final String className = handle.getOwner().replace('/', '.');
Class<?> owner = Class.forName(className, false, classLoader);
switch (handle.getTag()) {
case H_INVOKESTATIC:
return lookup.findStatic(owner, handle.getName(), type);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright © 2013-2017 Esko Luontola and other Retrolambda contributors
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package net.orfjackal.retrolambda;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.function.Function;
import org.junit.Assert;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;

public class FunctionTest {
@Test
public void convertFunction() throws Throwable {
InputStream is = Function.class.getResourceAsStream("Function.class");
assertNotNull("Bytecode of Function found", is);

byte[] oldB = readFully(is);

ClassAnalyzer analyzer = new ClassAnalyzer();
Transformers transformers = new Transformers(Opcodes.V1_7, true, analyzer);
try {
byte[] newB = transformers.backportClass(new ClassReader(oldB));
assertNotNull("No exception", newB);
Assert.assertNotEquals("Different", oldB, newB);
} catch (RuntimeException ex) {
Throwable t = ex;
while (t != null) {
if (t instanceof IllegalArgumentException) {
throw t;
}
t = t.getCause();
}
}
}

static byte[] readFully(InputStream is) throws IOException {
if (is == null) {
throw new IOException();
}
byte[] arr = new byte[4096 * 4096];
int off = 0;
for (;;) {
int len = is.read(arr, off, arr.length - off);
if (len == -1) {
break;
}
off += len;
}
return Arrays.copyOf(arr, off);
}
}