Skip to content

Commit

Permalink
Refactored: created ClassInfo and MethodSignature
Browse files Browse the repository at this point in the history
  • Loading branch information
luontola committed Mar 23, 2015
1 parent 3556a2b commit 118f68e
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
package net.orfjackal.retrolambda;

import net.orfjackal.retrolambda.files.*;
import net.orfjackal.retrolambda.interfaces.ClassHierarchyAnalyzer;
import net.orfjackal.retrolambda.interfaces.*;
import net.orfjackal.retrolambda.lambdas.*;
import org.objectweb.asm.ClassReader;

import java.io.IOException;
import java.net.*;
Expand Down Expand Up @@ -57,12 +56,12 @@ protected void visit(byte[] bytecode) {
});

List<byte[]> transformed = new ArrayList<>();
for (ClassReader reader : analyzer.getInterfaces()) {
transformed.add(transformers.extractInterfaceCompanion(reader));
transformed.add(transformers.backportInterface(reader));
for (ClassInfo c : analyzer.getInterfaces()) {
transformed.add(transformers.extractInterfaceCompanion(c.reader));
transformed.add(transformers.backportInterface(c.reader));
}
for (ClassReader reader : analyzer.getClasses()) {
transformed.add(transformers.backportClass(reader));
for (ClassInfo c : analyzer.getClasses()) {
transformed.add(transformers.backportClass(c.reader));
}

// We need to load some of the classes (for calling the lambda metafactory)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2013-2014 Esko Luontola <www.orfjackal.net>
// Copyright © 2013-2015 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

Expand All @@ -17,28 +17,23 @@ public class ClassHierarchyAnalyzer implements MethodRelocations {

private static final MethodRef ABSTRACT_METHOD = new MethodRef("", "", "");

private final List<ClassReader> interfaces = new ArrayList<>();
private final List<ClassReader> classes = new ArrayList<>();
private final Map<Type, ClassInfo> classes = new HashMap<>();
@Deprecated
private final Map<String, String> superclasses = new HashMap<>();
private final Map<Type, List<Type>> interfacesByImplementer = new HashMap<>(); // TODO: could use just String instead of Type
@Deprecated
private final Map<String, List<MethodRef>> methodsByInterface = new HashMap<>();
@Deprecated
private final Map<String, List<MethodRef>> methodsByClass = new HashMap<>();
private final Map<MethodRef, MethodRef> relocatedMethods = new HashMap<>();
private final Map<MethodRef, MethodRef> methodDefaultImpls = new HashMap<>();
private final Map<String, String> companionClasses = new HashMap<>();

public void analyze(byte[] bytecode) {
ClassReader cr = new ClassReader(bytecode);
Type clazz = classNameToType(cr.getClassName());

if (Flags.hasFlag(cr.getAccess(), ACC_INTERFACE)) {
interfaces.add(cr);
} else {
classes.add(cr);
}
ClassInfo c = new ClassInfo(cr);
classes.put(c.type, c);

List<Type> interfaces = classNamesToTypes(cr.getInterfaces());
interfacesByImplementer.put(clazz, interfaces);
superclasses.put(cr.getClassName(), cr.getSuperName());

if (Flags.hasFlag(cr.getAccess(), ACC_INTERFACE)) {
Expand Down Expand Up @@ -119,16 +114,27 @@ private boolean isDefaultMethod(int access) {
}, ClassReader.SKIP_CODE);
}

public List<ClassReader> getInterfaces() {
return interfaces;
public List<ClassInfo> getInterfaces() {
return classes.values()
.stream()
.filter(ClassInfo::isInterface)
.collect(toList());
}

public List<ClassReader> getClasses() {
return classes;
public List<ClassInfo> getClasses() {
return classes.values()
.stream()
.filter(ClassInfo::isClass)
.collect(toList());
}

public List<Type> getInterfacesOf(Type type) {
return interfacesByImplementer.getOrDefault(type, Collections.emptyList());
ClassInfo c = classes.get(type);
if (c == null) {
// non-analyzed class, probably from a class library
return Collections.emptyList();
}
return c.interfaces;
}

@Override
Expand All @@ -152,7 +158,7 @@ public MethodRef getMethodDefaultImplementation(MethodRef interfaceMethod) {
if (impl != null) {
return impl;
}
parentInterfaces.addAll(interfacesByImplementer.getOrDefault(anInterface, Collections.emptyList()));
parentInterfaces.addAll(getInterfacesOf(anInterface));
}
currentInterfaces = parentInterfaces;
parentInterfaces = new ArrayList<>();
Expand Down Expand Up @@ -187,13 +193,13 @@ public String getCompanionClass(String className) {
return companionClasses.get(className);
}

private static List<Type> classNamesToTypes(String[] interfaces) {
static List<Type> classNamesToTypes(String[] interfaces) {
return Stream.of(interfaces)
.map(ClassHierarchyAnalyzer::classNameToType)
.collect(toList());
}

private static Type classNameToType(String className) {
static Type classNameToType(String className) {
return Type.getType("L" + className + ";");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright © 2013-2015 Esko Luontola <www.orfjackal.net>
// 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.interfaces;

import net.orfjackal.retrolambda.util.Flags;
import org.objectweb.asm.*;

import java.util.List;

import static net.orfjackal.retrolambda.interfaces.ClassHierarchyAnalyzer.*;
import static org.objectweb.asm.Opcodes.ACC_INTERFACE;

public class ClassInfo {

public final ClassReader reader;
private final int access;
public final Type type;
public final Type superclass;
public final List<Type> interfaces;

public ClassInfo(ClassReader cr) {
this.reader = cr;
this.access = cr.getAccess();
this.type = classNameToType(cr.getClassName());
this.superclass = classNameToType(cr.getSuperName());
this.interfaces = classNamesToTypes(cr.getInterfaces());
}

public boolean isClass() {
return !isInterface();
}

public boolean isInterface() {
return Flags.hasFlag(access, ACC_INTERFACE);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2013-2014 Esko Luontola <www.orfjackal.net>
// Copyright © 2013-2015 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

Expand Down Expand Up @@ -26,6 +26,10 @@ public MethodRef(String owner, String name, String desc) {
this.name = name;
this.desc = desc;
}

public MethodSignature getSignature() {
return new MethodSignature(name, desc);
}

public MethodRef withOwner(String newOwner) {
return new MethodRef(newOwner, name, desc);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright © 2013-2015 Esko Luontola <www.orfjackal.net>
// 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.interfaces;

import com.google.common.base.MoreObjects;

import java.util.Objects;

public class MethodSignature {

public final String name;
public final String desc;

public MethodSignature(String desc, String name) {
this.name = name;
this.desc = desc;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof MethodSignature)) {
return false;
}
MethodSignature that = (MethodSignature) obj;
return this.name.equals(that.name)
&& this.desc.equals(that.desc);
}

@Override
public int hashCode() {
return Objects.hash(name, desc);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.addValue(name)
.addValue(desc)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2013-2014 Esko Luontola <www.orfjackal.net>
// Copyright © 2013-2015 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

Expand All @@ -7,7 +7,7 @@
import com.google.common.io.ByteStreams;
import net.orfjackal.retrolambda.interfaces.*;
import org.junit.Test;
import org.objectweb.asm.*;
import org.objectweb.asm.Type;

import java.io.*;
import java.util.*;
Expand Down Expand Up @@ -259,11 +259,11 @@ private void analyze(Class<?>... classes) {
}

private List<Class<?>> getInterfaces() {
return readersToClasses(analyzer.getInterfaces());
return infosToClasses(analyzer.getInterfaces());
}

private List<Class<?>> getClasses() {
return readersToClasses(analyzer.getClasses());
return infosToClasses(analyzer.getClasses());
}

private List<Class<?>> getInterfacesOf(Class<?> clazz) {
Expand All @@ -280,8 +280,8 @@ private static String voidMethod(Class<?>... argumentTypes) {
.toArray(Type[]::new));
}

private static List<Class<?>> readersToClasses(List<ClassReader> readers) {
return readers.stream()
private static List<Class<?>> infosToClasses(List<ClassInfo> classes) {
return classes.stream()
.map(ClassHierarchyAnalyzerTest::toClass)
.collect(toList());
}
Expand All @@ -296,9 +296,9 @@ private static List<Class<?>> classList(Class<?>... aClass) {
return asList(aClass);
}

private static Class<?> toClass(ClassReader reader) {
private static Class<?> toClass(ClassInfo c) {
try {
return Class.forName(reader.getClassName().replace('/', '.'));
return Class.forName(c.type.getClassName().replace('/', '.'));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Expand Down

0 comments on commit 118f68e

Please sign in to comment.