Use a class reference for interface methods in the vtable

This commit is contained in:
Ben Gruver 2016-09-18 19:07:15 -07:00
parent 41ba26d00a
commit 815f023e4e

View File

@ -39,12 +39,10 @@ import com.google.common.collect.*;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.analysis.util.TypeProtoUtils; import org.jf.dexlib2.analysis.util.TypeProtoUtils;
import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.base.reference.BaseMethodReference;
import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.util.MethodUtil; import org.jf.dexlib2.util.MethodUtil;
import org.jf.util.AlignmentUtils; import org.jf.util.AlignmentUtils;
import org.jf.util.ExceptionWithContext; import org.jf.util.ExceptionWithContext;
@ -886,15 +884,7 @@ public class ClassProto implements TypeProto {
for (ClassDef interfaceDef: interfaces) { for (ClassDef interfaceDef: interfaces) {
List<Method> interfaceMethods = Lists.newArrayList(); List<Method> interfaceMethods = Lists.newArrayList();
for (Method interfaceMethod: interfaceDef.getVirtualMethods()) { for (Method interfaceMethod: interfaceDef.getVirtualMethods()) {
ImmutableMethod method = new ImmutableMethod( interfaceMethods.add(new ReparentedMethod(interfaceMethod, type));
type,
interfaceMethod.getName(),
interfaceMethod.getParameters(),
interfaceMethod.getReturnType(),
interfaceMethod.getAccessFlags(),
interfaceMethod.getAnnotations(),
interfaceMethod.getImplementation());
interfaceMethods.add(method);
} }
addToVtable(interfaceMethods, vtable, false, true); addToVtable(interfaceMethods, vtable, false, true);
} }
@ -921,8 +911,8 @@ public class ClassProto implements TypeProto {
ClassProto superclass = (ClassProto) classPath.getClass(superclassType); ClassProto superclass = (ClassProto) classPath.getClass(superclassType);
vtable.addAll(superclass.getVtable()); vtable.addAll(superclass.getVtable());
// if the superclass's vtable wasn't fully resolved, then we can't know where the new methods added by this // if the superclass's vtable wasn't fully resolved, then we can't know where the new methods added by
// class should start, so we just propagate what we can from the parent and hope for the best. // this class should start, so we just propagate what we can from the parent and hope for the best.
if (!superclass.vtableFullyResolved) { if (!superclass.vtableFullyResolved) {
vtableFullyResolved = false; vtableFullyResolved = false;
return vtable; return vtable;
@ -971,17 +961,16 @@ public class ClassProto implements TypeProto {
if (mirandaMethodIndex >= 0) { if (mirandaMethodIndex >= 0) {
if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) {
mirandaMethods.remove(mirandaMethodIndex); Method removedMethod = mirandaMethods.remove(mirandaMethodIndex);
defaultMethods.add(interfaceMethod); defaultMethods.add(removedMethod);
} }
} }
if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) {
defaultMethods.add(interfaceMethod); defaultMethods.add(new ReparentedMethod(interfaceMethod, type));
} else { } else {
mirandaMethods.add(interfaceMethod); mirandaMethods.add(new ReparentedMethod(interfaceMethod, type));
} }
} }
} }
} }
@ -1028,4 +1017,46 @@ public class ClassProto implements TypeProto {
return 2; //OTHER return 2; //OTHER
} }
} }
static class ReparentedMethod extends BaseMethodReference implements Method {
private final Method method;
private final String definingClass;
public ReparentedMethod(Method method, String definingClass) {
this.method = method;
this.definingClass = definingClass;
}
@Nonnull @Override public String getDefiningClass() {
return definingClass;
}
@Nonnull @Override public String getName() {
return method.getName();
}
@Nonnull @Override public List<? extends CharSequence> getParameterTypes() {
return method.getParameterTypes();
}
@Nonnull @Override public String getReturnType() {
return method.getReturnType();
}
@Nonnull @Override public List<? extends MethodParameter> getParameters() {
return method.getParameters();
}
@Override public int getAccessFlags() {
return method.getAccessFlags();
}
@Nonnull @Override public Set<? extends Annotation> getAnnotations() {
return method.getAnnotations();
}
@Nullable @Override public MethodImplementation getImplementation() {
return method.getImplementation();
}
}
} }