mirror of
https://github.com/revanced/smali.git
synced 2025-05-22 00:37:04 +02:00
Refactor dexbacked implementations
Made construction of a new dexbacked item as light weight as possible, only the very mimimum in computed/stored. Some of the values that were previously calculated/loaded in the constructor are now lazily loaded upon first use. In general, nothing is cached, unless the item can't be fully read by the consumer without causing the value to be computed multiple times. Otherwise, it is up to the consume to decide if/when/what they want to cache.
This commit is contained in:
parent
8ae711cf3b
commit
d1662b67fe
@ -28,6 +28,7 @@
|
||||
|
||||
package org.jf.baksmali.Adaptors;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
|
||||
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
@ -52,6 +53,7 @@ public class MethodDefinition {
|
||||
@Nonnull public final ClassDefinition classDef;
|
||||
@Nonnull public final Method method;
|
||||
@Nonnull public final MethodImplementation methodImpl;
|
||||
@Nonnull public final ImmutableList<Instruction> instructions;
|
||||
public RegisterFormatter registerFormatter;
|
||||
|
||||
@Nonnull private final String methodString;
|
||||
@ -73,11 +75,11 @@ public class MethodDefinition {
|
||||
try {
|
||||
//TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
|
||||
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
instructions = ImmutableList.copyOf(methodImpl.getInstructions());
|
||||
|
||||
packedSwitchMap = new SparseIntArray(0);
|
||||
sparseSwitchMap = new SparseIntArray(0);
|
||||
instructionOffsetMap = new InstructionOffsetMap(methodImpl);
|
||||
instructionOffsetMap = new InstructionOffsetMap(instructions);
|
||||
|
||||
for (int i=0; i<instructions.size(); i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
@ -178,7 +180,6 @@ public class MethodDefinition {
|
||||
//TODO: does dalvik let you pad with multiple nops?
|
||||
//TODO: does dalvik let a switch instruction point to a non-payload instruction?
|
||||
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
Instruction instruction = instructions.get(targetIndex);
|
||||
if (instruction.getOpcode() != type) {
|
||||
// maybe it's pointing to a NOP padding instruction. Look at the next instruction
|
||||
@ -276,8 +277,6 @@ public class MethodDefinition {
|
||||
}
|
||||
|
||||
private void addInstructionMethodItems(List<MethodItem> methodItems) {
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
|
||||
int currentCodeAddress = 0;
|
||||
for (int i=0; i<instructions.size(); i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
@ -407,7 +406,6 @@ public class MethodDefinition {
|
||||
return;
|
||||
}
|
||||
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
|
||||
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class DexBackedAnnotation implements Annotation {
|
||||
@Nonnull public final DexBuffer dexBuf;
|
||||
|
||||
public final int visibility;
|
||||
@Nonnull public final String type;
|
||||
public final int typeIndex;
|
||||
private final int elementsOffset;
|
||||
|
||||
public DexBackedAnnotation(@Nonnull DexBuffer dexBuf,
|
||||
@ -51,12 +51,12 @@ public class DexBackedAnnotation implements Annotation {
|
||||
|
||||
DexReader reader = dexBuf.readerAt(annotationOffset);
|
||||
this.visibility = reader.readUbyte();
|
||||
this.type = reader.getType(reader.readSmallUleb128());
|
||||
this.typeIndex = reader.readSmallUleb128();
|
||||
this.elementsOffset = reader.getOffset();
|
||||
}
|
||||
|
||||
@Override public int getVisibility() { return visibility; }
|
||||
@Nonnull @Override public String getType() { return type; }
|
||||
@Nonnull @Override public String getType() { return dexBuf.getType(typeIndex); }
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
|
@ -38,11 +38,13 @@ import org.jf.dexlib2.iface.value.EncodedValue;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class DexBackedAnnotationElement implements AnnotationElement {
|
||||
@Nonnull public final String name;
|
||||
@Nonnull private final DexBuffer dexBuffer;
|
||||
public final int nameIndex;
|
||||
@Nonnull public final EncodedValue value;
|
||||
|
||||
public DexBackedAnnotationElement(@Nonnull DexReader reader) {
|
||||
this.name = reader.getString(reader.readSmallUleb128());
|
||||
this.dexBuffer = reader.getDexBuffer();
|
||||
this.nameIndex = reader.readSmallUleb128();
|
||||
this.value = DexBackedEncodedValue.readFrom(reader);
|
||||
}
|
||||
|
||||
@ -51,6 +53,6 @@ public class DexBackedAnnotationElement implements AnnotationElement {
|
||||
DexBackedEncodedValue.skipFrom(reader);
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getName() { return name; }
|
||||
@Nonnull @Override public String getName() { return dexBuffer.getString(nameIndex); }
|
||||
@Nonnull @Override public EncodedValue getValue() { return value; }
|
||||
}
|
||||
|
@ -31,16 +31,20 @@
|
||||
|
||||
package org.jf.dexlib2.dexbacked;
|
||||
|
||||
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
|
||||
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DexBackedCatchAllExceptionHandler implements ExceptionHandler {
|
||||
private final int handlerCodeOffset;
|
||||
|
||||
public class DexBackedCatchAllExceptionHandler extends ImmutableExceptionHandler {
|
||||
public DexBackedCatchAllExceptionHandler(@Nonnull DexReader reader) {
|
||||
super(null, reader.readSmallUleb128());
|
||||
this.handlerCodeOffset = reader.readSmallUleb128();
|
||||
}
|
||||
|
||||
public static void skipFrom(@Nonnull DexReader reader) {
|
||||
reader.skipUleb128();
|
||||
}
|
||||
@Nullable @Override public String getExceptionType() { return null; }
|
||||
@Override public int getHandlerCodeOffset() { return handlerCodeOffset; }
|
||||
|
||||
public static void skipFrom(@Nonnull DexReader reader) { reader.skipUleb128(); }
|
||||
}
|
||||
|
@ -41,19 +41,14 @@ import java.util.List;
|
||||
|
||||
public class DexBackedClassDef implements ClassDef {
|
||||
@Nonnull public final DexBuffer dexBuf;
|
||||
private final int classDefOffset;
|
||||
|
||||
@Nonnull public final String name;
|
||||
public final int accessFlags;
|
||||
@Nullable public final String superclass;
|
||||
@Nullable public final String sourceFile;
|
||||
private int classDataOffset = -1;
|
||||
|
||||
@Nonnull private final AnnotationsDirectory annotationsDirectory;
|
||||
private final int staticInitialValuesOffset;
|
||||
|
||||
private final int interfacesOffset;
|
||||
private final int classDataOffset;
|
||||
@Nullable private AnnotationsDirectory annotationsDirectory;
|
||||
|
||||
//class_def_item offsets
|
||||
private static final int CLASS_NAME_OFFSET = 0;
|
||||
private static final int ACCESS_FLAGS_OFFSET = 4;
|
||||
private static final int SUPERCLASS_OFFSET = 8;
|
||||
private static final int INTERFACES_OFFSET = 12;
|
||||
@ -65,29 +60,36 @@ public class DexBackedClassDef implements ClassDef {
|
||||
public DexBackedClassDef(@Nonnull DexBuffer dexBuf,
|
||||
int classDefOffset) {
|
||||
this.dexBuf = dexBuf;
|
||||
|
||||
this.name = dexBuf.getType(dexBuf.readSmallUint(classDefOffset));
|
||||
this.accessFlags = dexBuf.readSmallUint(classDefOffset + ACCESS_FLAGS_OFFSET);
|
||||
this.superclass = dexBuf.getOptionalType(dexBuf.readOptionalUint(classDefOffset + SUPERCLASS_OFFSET));
|
||||
this.interfacesOffset = dexBuf.readSmallUint(classDefOffset + INTERFACES_OFFSET);
|
||||
this.sourceFile = dexBuf.getOptionalString(dexBuf.readOptionalUint(classDefOffset + SOURCE_FILE_OFFSET));
|
||||
|
||||
int annotationsDirectoryOffset = dexBuf.readSmallUint(classDefOffset + ANNOTATIONS_OFFSET);
|
||||
this.annotationsDirectory = AnnotationsDirectory.newOrEmpty(dexBuf, annotationsDirectoryOffset);
|
||||
|
||||
this.classDataOffset = dexBuf.readSmallUint(classDefOffset + CLASS_DATA_OFFSET);
|
||||
this.staticInitialValuesOffset = dexBuf.readSmallUint(classDefOffset + STATIC_INITIAL_VALUES_OFFSET);
|
||||
this.classDefOffset = classDefOffset;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return dexBuf.getType(dexBuf.readSmallUint(classDefOffset + CLASS_NAME_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getName() { return name; }
|
||||
@Override public int getAccessFlags() { return accessFlags; }
|
||||
@Nullable @Override public String getSuperclass() { return superclass; }
|
||||
@Nullable @Override public String getSourceFile() { return sourceFile; }
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSuperclass() {
|
||||
return dexBuf.getOptionalType(dexBuf.readOptionalUint(classDefOffset + SUPERCLASS_OFFSET));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAccessFlags() {
|
||||
return dexBuf.readSmallUint(classDefOffset + ACCESS_FLAGS_OFFSET);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSourceFile() {
|
||||
return dexBuf.getOptionalString(dexBuf.readOptionalUint(classDefOffset + SOURCE_FILE_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<String> getInterfaces() {
|
||||
final int interfacesOffset = dexBuf.readSmallUint(classDefOffset + INTERFACES_OFFSET);
|
||||
if (interfacesOffset > 0) {
|
||||
final int size = dexBuf.readSmallUint(interfacesOffset);
|
||||
return new FixedSizeList<String>() {
|
||||
@ -106,13 +108,14 @@ public class DexBackedClassDef implements ClassDef {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends DexBackedAnnotation> getAnnotations() {
|
||||
return annotationsDirectory.getClassAnnotations();
|
||||
return getAnnotationsDirectory().getClassAnnotations();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends DexBackedField> getFields() {
|
||||
if (classDataOffset != 0) {
|
||||
int classDataOffset = getClassDataOffset();
|
||||
if (getClassDataOffset() != 0) {
|
||||
DexReader reader = dexBuf.readerAt(classDataOffset);
|
||||
final int staticFieldCount = reader.readSmallUleb128();
|
||||
int instanceFieldCount = reader.readSmallUleb128();
|
||||
@ -121,13 +124,16 @@ public class DexBackedClassDef implements ClassDef {
|
||||
reader.skipUleb128(); //direct_methods_size
|
||||
reader.skipUleb128(); //virtual_methods_size
|
||||
|
||||
final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory();
|
||||
final int staticInitialValuesOffset =
|
||||
dexBuf.readSmallUint(classDefOffset + STATIC_INITIAL_VALUES_OFFSET);
|
||||
final int fieldsStartOffset = reader.getOffset();
|
||||
|
||||
return new VariableSizeListWithContext<DexBackedField>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterator listIterator() {
|
||||
return new Iterator(dexBuf, fieldsStartOffset) {
|
||||
public VariableSizeListIterator listIterator() {
|
||||
return new VariableSizeListIterator(dexBuf, fieldsStartOffset) {
|
||||
private int previousFieldIndex = 0;
|
||||
@Nonnull private final AnnotationsDirectory.AnnotationIterator annotationIterator =
|
||||
annotationsDirectory.getFieldAnnotationIterator();
|
||||
@ -173,6 +179,7 @@ public class DexBackedClassDef implements ClassDef {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends DexBackedMethod> getMethods() {
|
||||
int classDataOffset = getClassDataOffset();
|
||||
if (classDataOffset > 0) {
|
||||
DexReader reader = dexBuf.readerAt(classDataOffset);
|
||||
int staticFieldCount = reader.readSmallUleb128();
|
||||
@ -183,13 +190,14 @@ public class DexBackedClassDef implements ClassDef {
|
||||
if (methodCount > 0) {
|
||||
DexBackedField.skipAllFields(reader, staticFieldCount + instanceFieldCount);
|
||||
|
||||
final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory();
|
||||
final int methodsStartOffset = reader.getOffset();
|
||||
|
||||
return new VariableSizeListWithContext<DexBackedMethod>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterator listIterator() {
|
||||
return new Iterator(dexBuf, methodsStartOffset) {
|
||||
public VariableSizeListIterator listIterator() {
|
||||
return new VariableSizeListIterator(dexBuf, methodsStartOffset) {
|
||||
private int previousMethodIndex = 0;
|
||||
@Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator =
|
||||
annotationsDirectory.getMethodAnnotationIterator();
|
||||
@ -232,4 +240,19 @@ public class DexBackedClassDef implements ClassDef {
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
private int getClassDataOffset() {
|
||||
if (classDataOffset == -1) {
|
||||
classDataOffset = dexBuf.readSmallUint(classDefOffset + CLASS_DATA_OFFSET);
|
||||
}
|
||||
return classDataOffset;
|
||||
}
|
||||
|
||||
private AnnotationsDirectory getAnnotationsDirectory() {
|
||||
if (annotationsDirectory == null) {
|
||||
int annotationsDirectoryOffset = dexBuf.readSmallUint(classDefOffset + ANNOTATIONS_OFFSET);
|
||||
annotationsDirectory = AnnotationsDirectory.newOrEmpty(dexBuf, annotationsDirectoryOffset);
|
||||
}
|
||||
return annotationsDirectory;
|
||||
}
|
||||
}
|
||||
|
@ -31,24 +31,24 @@
|
||||
|
||||
package org.jf.dexlib2.dexbacked;
|
||||
|
||||
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
|
||||
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class DexBackedExceptionHandler extends ImmutableExceptionHandler {
|
||||
private DexBackedExceptionHandler(String exceptionType, int handlerCodeOffset) {
|
||||
public class DexBackedExceptionHandler implements ExceptionHandler {
|
||||
@Nonnull private final DexBuffer dexBuf;
|
||||
private final int typeId;
|
||||
private final int handlerCodeOffset;
|
||||
|
||||
public DexBackedExceptionHandler(@Nonnull DexReader reader) {
|
||||
// TODO: verify dalvik doesn't accept an exception handler that points in the middle of an instruction
|
||||
super(exceptionType, handlerCodeOffset);
|
||||
this.dexBuf = reader.getDexBuffer();
|
||||
this.typeId = reader.readSmallUleb128();
|
||||
this.handlerCodeOffset = reader.readSmallUleb128();
|
||||
}
|
||||
|
||||
// static factory method, because we can't read from the reader in the correct order while calling super() in the
|
||||
// constructor. ugh.
|
||||
public static DexBackedExceptionHandler createNew(@Nonnull DexReader reader) {
|
||||
int typeId = reader.readSmallUleb128();
|
||||
String exceptionType = reader.getType(typeId);
|
||||
int handlerCodeOffset = reader.readSmallUleb128();
|
||||
return new DexBackedExceptionHandler(exceptionType, handlerCodeOffset);
|
||||
}
|
||||
@Nonnull @Override public String getExceptionType() { return dexBuf.getType(typeId); }
|
||||
@Override public int getHandlerCodeOffset() { return handlerCodeOffset; }
|
||||
|
||||
public static void skipFrom(@Nonnull DexReader reader) {
|
||||
reader.skipUleb128();
|
||||
|
@ -43,14 +43,14 @@ import java.util.List;
|
||||
public class DexBackedField implements Field {
|
||||
@Nonnull public final DexBuffer dexBuf;
|
||||
|
||||
@Nonnull public final String name;
|
||||
@Nonnull public final String type;
|
||||
public final int accessFlags;
|
||||
@Nullable public final EncodedValue initialValue;
|
||||
public final int annotationSetOffset;
|
||||
|
||||
public final int fieldIndex;
|
||||
|
||||
private int fieldIdItemOffset;
|
||||
|
||||
// offsets for field_id_item
|
||||
private static final int TYPE_OFFSET = 2;
|
||||
private static final int NAME_OFFSET = 4;
|
||||
@ -67,14 +67,20 @@ public class DexBackedField implements Field {
|
||||
|
||||
this.annotationSetOffset = annotationIterator.seekTo(fieldIndex);
|
||||
this.initialValue = staticInitialValueIterator.getNextOrNull();
|
||||
|
||||
int fieldIdItemOffset = reader.getFieldIdItemOffset(fieldIndex);
|
||||
this.type = reader.getType(reader.readUshort(fieldIdItemOffset + TYPE_OFFSET));
|
||||
this.name = reader.getString(reader.readSmallUint(fieldIdItemOffset + NAME_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getName() { return name; }
|
||||
@Nonnull @Override public String getType() { return type; }
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return dexBuf.getString(dexBuf.readSmallUint(getFieldIdItemOffset() + NAME_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getType() {
|
||||
return dexBuf.getType(dexBuf.readUshort(getFieldIdItemOffset() + TYPE_OFFSET));
|
||||
}
|
||||
|
||||
@Override public int getAccessFlags() { return accessFlags; }
|
||||
@Nullable @Override public EncodedValue getInitialValue() { return initialValue; }
|
||||
|
||||
@ -108,4 +114,11 @@ public class DexBackedField implements Field {
|
||||
reader.skipUleb128();
|
||||
}
|
||||
}
|
||||
|
||||
private int getFieldIdItemOffset() {
|
||||
if (fieldIdItemOffset == 0) {
|
||||
fieldIdItemOffset = dexBuf.getFieldIdItemOffset(fieldIndex);
|
||||
}
|
||||
return fieldIdItemOffset;
|
||||
}
|
||||
}
|
||||
|
@ -46,17 +46,18 @@ public class DexBackedMethod implements Method {
|
||||
@Nonnull public final DexBuffer dexBuf;
|
||||
@Nonnull public final DexBackedClassDef classDef;
|
||||
|
||||
@Nonnull public final String name;
|
||||
public final int accessFlags;
|
||||
@Nonnull public final String returnType;
|
||||
|
||||
private final int codeOffset;
|
||||
private final int parametersOffset;
|
||||
private final int parameterAnnotationSetListOffset;
|
||||
private final int methodAnnotationSetOffset;
|
||||
private final List<List<? extends DexBackedAnnotation>> parameterAnnotations;
|
||||
|
||||
public final int methodIndex;
|
||||
|
||||
private int methodIdItemOffset;
|
||||
private int protoIdItemOffset;
|
||||
private int parametersOffset = -1;
|
||||
|
||||
// method_id_item offsets
|
||||
private static final int PROTO_OFFSET = 2;
|
||||
private static final int NAME_OFFSET = 4;
|
||||
@ -65,6 +66,21 @@ public class DexBackedMethod implements Method {
|
||||
private static final int RETURN_TYPE_OFFSET = 4;
|
||||
private static final int PARAMETERS_OFFSET = 8;
|
||||
|
||||
public DexBackedMethod(@Nonnull DexReader reader,
|
||||
@Nonnull DexBackedClassDef classDef,
|
||||
int previousMethodIndex) {
|
||||
this.dexBuf = reader.getDexBuffer();
|
||||
this.classDef = classDef;
|
||||
|
||||
int methodIndexDiff = reader.readSmallUleb128();
|
||||
this.methodIndex = methodIndexDiff + previousMethodIndex;
|
||||
this.accessFlags = reader.readSmallUleb128();
|
||||
this.codeOffset = reader.readSmallUleb128();
|
||||
|
||||
this.methodAnnotationSetOffset = 0;
|
||||
this.parameterAnnotationSetListOffset = 0;
|
||||
}
|
||||
|
||||
public DexBackedMethod(@Nonnull DexReader reader,
|
||||
@Nonnull DexBackedClassDef classDef,
|
||||
int previousMethodIndex,
|
||||
@ -79,29 +95,27 @@ public class DexBackedMethod implements Method {
|
||||
this.codeOffset = reader.readSmallUleb128();
|
||||
|
||||
this.methodAnnotationSetOffset = methodAnnotationIterator.seekTo(methodIndex);
|
||||
int parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex);
|
||||
this.parameterAnnotations =
|
||||
AnnotationsDirectory.getParameterAnnotations(dexBuf, parameterAnnotationSetListOffset);
|
||||
|
||||
int methodIdItemOffset = reader.getMethodIdItemOffset(methodIndex);
|
||||
int protoIndex = reader.readUshort(methodIdItemOffset + PROTO_OFFSET);
|
||||
int protoIdItemOffset = reader.getProtoIdItemOffset(protoIndex);
|
||||
|
||||
this.name = reader.getString(reader.readSmallUint(methodIdItemOffset + NAME_OFFSET));
|
||||
|
||||
this.returnType = reader.getType(reader.readSmallUint(protoIdItemOffset + RETURN_TYPE_OFFSET));
|
||||
this.parametersOffset = reader.readSmallUint(protoIdItemOffset + PARAMETERS_OFFSET);
|
||||
this.parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex);
|
||||
}
|
||||
|
||||
|
||||
@Nonnull @Override public String getName() { return name; }
|
||||
@Override public int getAccessFlags() { return accessFlags; }
|
||||
@Nonnull @Override public String getReturnType() { return returnType; }
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return dexBuf.getString(dexBuf.readSmallUint(getMethodIdItemOffset() + NAME_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return dexBuf.getType(dexBuf.readSmallUint(getProtoIdItemOffset() + RETURN_TYPE_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends MethodParameter> getParameters() {
|
||||
if (parametersOffset > 0) {
|
||||
if (getParametersOffset() > 0) {
|
||||
DexBackedMethodImplementation methodImpl = getImplementation();
|
||||
if (methodImpl != null) {
|
||||
return methodImpl.getParametersWithNames();
|
||||
@ -113,8 +127,11 @@ public class DexBackedMethod implements Method {
|
||||
|
||||
@Nonnull
|
||||
public List<? extends MethodParameter> getParametersWithoutNames() {
|
||||
final int parametersOffset = getParametersOffset();
|
||||
if (parametersOffset > 0) {
|
||||
final int size = dexBuf.readSmallUint(parametersOffset);
|
||||
final List<List<? extends DexBackedAnnotation>> parameterAnnotations =
|
||||
AnnotationsDirectory.getParameterAnnotations(dexBuf, parameterAnnotationSetListOffset);
|
||||
|
||||
return new FixedSizeList<MethodParameter>() {
|
||||
@Nonnull
|
||||
@ -165,6 +182,28 @@ public class DexBackedMethod implements Method {
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getMethodIdItemOffset() {
|
||||
if (methodIdItemOffset == 0) {
|
||||
methodIdItemOffset = dexBuf.getMethodIdItemOffset(methodIndex);
|
||||
}
|
||||
return methodIdItemOffset;
|
||||
}
|
||||
|
||||
private int getProtoIdItemOffset() {
|
||||
if (protoIdItemOffset == 0) {
|
||||
int protoIndex = dexBuf.readUshort(getMethodIdItemOffset() + PROTO_OFFSET);
|
||||
protoIdItemOffset = dexBuf.getProtoIdItemOffset(protoIndex);
|
||||
}
|
||||
return protoIdItemOffset;
|
||||
}
|
||||
|
||||
private int getParametersOffset() {
|
||||
if (parametersOffset == -1) {
|
||||
parametersOffset = dexBuf.readSmallUint(getProtoIdItemOffset() + PARAMETERS_OFFSET);
|
||||
}
|
||||
return parametersOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the reader over a single encoded_method structure.
|
||||
* @param reader The {@code DexFileReader} to skip
|
||||
|
@ -35,8 +35,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction;
|
||||
import org.jf.dexlib2.dexbacked.util.DebugInfo;
|
||||
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
|
||||
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
|
||||
import org.jf.dexlib2.iface.Annotation;
|
||||
import org.jf.dexlib2.dexbacked.util.VariableSizeIterator;
|
||||
import org.jf.dexlib2.iface.MethodImplementation;
|
||||
import org.jf.dexlib2.iface.MethodParameter;
|
||||
import org.jf.dexlib2.iface.TryBlock;
|
||||
@ -45,8 +44,7 @@ import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.util.AlignmentUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class DexBackedMethodImplementation implements MethodImplementation {
|
||||
@ -54,10 +52,6 @@ public class DexBackedMethodImplementation implements MethodImplementation {
|
||||
@Nonnull public final DexBackedMethod method;
|
||||
private final int codeOffset;
|
||||
|
||||
public final int registerCount;
|
||||
@Nonnull public final ImmutableList<? extends Instruction> instructions;
|
||||
@Nonnull public final DebugInfo debugInfo;
|
||||
|
||||
// code_item offsets
|
||||
private static final int TRIES_SIZE_OFFSET = 6;
|
||||
private static final int DEBUG_OFFSET_OFFSET = 8;
|
||||
@ -72,13 +66,31 @@ public class DexBackedMethodImplementation implements MethodImplementation {
|
||||
this.dexBuf = dexBuf;
|
||||
this.method = method;
|
||||
this.codeOffset = codeOffset;
|
||||
this.registerCount = dexBuf.readUshort(codeOffset);
|
||||
this.instructions = buildInstructionList();
|
||||
this.debugInfo = DebugInfo.newOrEmpty(dexBuf, dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET), this);
|
||||
}
|
||||
|
||||
@Override public int getRegisterCount() { return registerCount; }
|
||||
@Nonnull @Override public ImmutableList<? extends Instruction> getInstructions() { return instructions; }
|
||||
@Override public int getRegisterCount() { return dexBuf.readUshort(codeOffset); }
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
|
||||
// instructionsSize is the number of 16-bit code units in the instruction list, not the number of instructions
|
||||
int instructionsSize = dexBuf.readSmallUint(codeOffset + INSTRUCTIONS_SIZE_OFFSET);
|
||||
|
||||
final int instructionsStartOffset = codeOffset + INSTRUCTIONS_START_OFFSET;
|
||||
final int endOffset = instructionsStartOffset + (instructionsSize*2);
|
||||
return new Iterable<Instruction>() {
|
||||
@Override
|
||||
public Iterator<Instruction> iterator() {
|
||||
return new VariableSizeIterator<Instruction>(dexBuf, instructionsStartOffset) {
|
||||
@Override
|
||||
protected Instruction readItem(@Nonnull DexReader reader, int index) {
|
||||
if (reader.getOffset() >= endOffset) {
|
||||
return null;
|
||||
}
|
||||
return DexBackedInstruction.readFrom(reader);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
@ -109,30 +121,17 @@ public class DexBackedMethodImplementation implements MethodImplementation {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
private DebugInfo getDebugInfo() {
|
||||
return DebugInfo.newOrEmpty(dexBuf, dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET), this);
|
||||
}
|
||||
|
||||
@Nonnull @Override
|
||||
public Iterable<? extends DebugItem> getDebugItems() {
|
||||
return debugInfo;
|
||||
return getDebugInfo();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private ImmutableList<? extends Instruction> buildInstructionList() {
|
||||
// instructionsSize is the number of 16-bit code units in the instruction list, not the number of instructions
|
||||
int instructionsSize = dexBuf.readSmallUint(codeOffset + INSTRUCTIONS_SIZE_OFFSET);
|
||||
|
||||
// we can use instructionsSize as an upper bound on the number of instructions there will be
|
||||
ArrayList<Instruction> instructions = new ArrayList<Instruction>(instructionsSize);
|
||||
int instructionsStartOffset = codeOffset + INSTRUCTIONS_START_OFFSET;
|
||||
DexReader reader = dexBuf.readerAt(instructionsStartOffset);
|
||||
int endOffset = instructionsStartOffset + (instructionsSize*2);
|
||||
|
||||
while (reader.getOffset() < endOffset) {
|
||||
instructions.add(DexBackedInstruction.readFrom(reader));
|
||||
}
|
||||
|
||||
return ImmutableList.copyOf(instructions);
|
||||
}
|
||||
|
||||
public List<? extends MethodParameter> getParametersWithNames() {
|
||||
return debugInfo.getParametersWithNames();
|
||||
return getDebugInfo().getParametersWithNames();
|
||||
}
|
||||
}
|
||||
|
@ -40,11 +40,8 @@ import java.util.List;
|
||||
|
||||
public class DexBackedTryBlock implements TryBlock {
|
||||
@Nonnull public final DexBuffer dexBuf;
|
||||
|
||||
public final int startCodeOffset;
|
||||
public final int codeUnitCount;
|
||||
|
||||
private final int exceptionHandlersOffset;
|
||||
private final int tryItemOffset;
|
||||
private final int handlersStartOffset;
|
||||
|
||||
private static final int START_ADDRESS_OFFSET = 0;
|
||||
private static final int CODE_UNIT_COUNT_OFFSET = 4;
|
||||
@ -54,18 +51,18 @@ public class DexBackedTryBlock implements TryBlock {
|
||||
int tryItemOffset,
|
||||
int handlersStartOffset) {
|
||||
this.dexBuf = dexBuf;
|
||||
this.startCodeOffset = dexBuf.readSmallUint(tryItemOffset + START_ADDRESS_OFFSET);
|
||||
this.codeUnitCount = dexBuf.readUshort(tryItemOffset + CODE_UNIT_COUNT_OFFSET);
|
||||
this.exceptionHandlersOffset = handlersStartOffset + dexBuf.readUshort(tryItemOffset + HANDLER_OFFSET_OFFSET);
|
||||
this.tryItemOffset = tryItemOffset;
|
||||
this.handlersStartOffset = handlersStartOffset;
|
||||
}
|
||||
|
||||
@Override public int getStartCodeOffset() { return startCodeOffset; }
|
||||
@Override public int getCodeUnitCount() { return codeUnitCount; }
|
||||
@Override public int getStartCodeOffset() { return dexBuf.readSmallUint(tryItemOffset + START_ADDRESS_OFFSET); }
|
||||
@Override public int getCodeUnitCount() { return dexBuf.readUshort(tryItemOffset + CODE_UNIT_COUNT_OFFSET); }
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends ExceptionHandler> getExceptionHandlers() {
|
||||
DexReader reader = dexBuf.readerAt(exceptionHandlersOffset);
|
||||
DexReader reader =
|
||||
dexBuf.readerAt(handlersStartOffset + dexBuf.readUshort(tryItemOffset + HANDLER_OFFSET_OFFSET));
|
||||
final int encodedSize = reader.readSleb128();
|
||||
|
||||
if (encodedSize > 0) {
|
||||
@ -74,7 +71,7 @@ public class DexBackedTryBlock implements TryBlock {
|
||||
@Nonnull
|
||||
@Override
|
||||
protected ExceptionHandler readItem(@Nonnull DexReader reader, int index) {
|
||||
return DexBackedExceptionHandler.createNew(reader);
|
||||
return new DexBackedExceptionHandler(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -94,7 +91,7 @@ public class DexBackedTryBlock implements TryBlock {
|
||||
if (index == sizeWithCatchAll-1) {
|
||||
return new DexBackedCatchAllExceptionHandler(dexReader);
|
||||
} else {
|
||||
return DexBackedExceptionHandler.createNew(dexReader);
|
||||
return new DexBackedExceptionHandler(dexReader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib2.dexbacked.util;
|
||||
|
||||
import org.jf.dexlib2.dexbacked.DexBuffer;
|
||||
import org.jf.dexlib2.dexbacked.DexReader;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Iterator;
|
||||
|
||||
public abstract class VariableSizeIterator<T> implements Iterator<T> {
|
||||
private final DexReader reader;
|
||||
|
||||
private int index = 0;
|
||||
private T cachedItem = null;
|
||||
|
||||
protected VariableSizeIterator(DexBuffer dexBuf, int offset) {
|
||||
this.reader = dexBuf.readerAt(offset);
|
||||
cachedItem = readItem(reader, index++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next item from reader. If the end of the list has been reached, it should return null.
|
||||
*
|
||||
* @param reader The {@code DexReader} to read from
|
||||
* @param index The index of the item that is being read
|
||||
* @return The item that was read, or null if the end of the list has been reached.
|
||||
*/
|
||||
@Nullable protected abstract T readItem(@Nonnull DexReader reader, int index);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return cachedItem != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
T ret = cachedItem;
|
||||
cachedItem = readItem(reader, index++);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override public void remove() { throw new UnsupportedOperationException(); }
|
||||
}
|
@ -51,8 +51,8 @@ import java.util.NoSuchElementException;
|
||||
public abstract class VariableSizeListWithContext<T> extends AbstractSequentialList<T> {
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterator listIterator(int startIndex) {
|
||||
Iterator iterator = listIterator();
|
||||
public VariableSizeListIterator listIterator(int startIndex) {
|
||||
VariableSizeListIterator iterator = listIterator();
|
||||
if (startIndex < 0 || startIndex >= size()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
@ -62,13 +62,13 @@ public abstract class VariableSizeListWithContext<T> extends AbstractSequentialL
|
||||
return iterator;
|
||||
}
|
||||
|
||||
@Nonnull @Override public abstract Iterator listIterator();
|
||||
@Nonnull @Override public abstract VariableSizeListIterator listIterator();
|
||||
|
||||
public abstract class Iterator extends AbstractListIterator<T> {
|
||||
public abstract class VariableSizeListIterator extends AbstractListIterator<T> {
|
||||
private int index = 0;
|
||||
@Nonnull private final DexReader reader;
|
||||
|
||||
public Iterator(@Nonnull DexBuffer dexBuf, int offset) {
|
||||
public VariableSizeListIterator(@Nonnull DexBuffer dexBuf, int offset) {
|
||||
this.reader = dexBuf.readerAt(offset);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ import java.util.List;
|
||||
|
||||
public interface MethodImplementation {
|
||||
int getRegisterCount();
|
||||
@Nonnull List<? extends Instruction> getInstructions();
|
||||
@Nonnull Iterable<? extends Instruction> getInstructions();
|
||||
@Nonnull List<? extends TryBlock> getTryBlocks();
|
||||
@Nonnull Iterable<? extends DebugItem> getDebugItems();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class ImmutableMethodImplementation implements MethodImplementation {
|
||||
@Nonnull public final ImmutableList<? extends ImmutableDebugItem> debugItems;
|
||||
|
||||
public ImmutableMethodImplementation(int registerCount,
|
||||
@Nullable List<? extends Instruction> instructions,
|
||||
@Nullable Iterable<? extends Instruction> instructions,
|
||||
@Nullable List<? extends TryBlock> tryBlocks,
|
||||
@Nullable Iterable<? extends DebugItem> debugItems) {
|
||||
this.registerCount = registerCount;
|
||||
|
@ -131,7 +131,7 @@ public abstract class ImmutableInstruction implements Instruction {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ImmutableList<ImmutableInstruction> immutableListOf(List<? extends Instruction> list) {
|
||||
public static ImmutableList<ImmutableInstruction> immutableListOf(Iterable<? extends Instruction> list) {
|
||||
return CONVERTER.convert(list);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
package org.jf.dexlib2.util;
|
||||
|
||||
import org.jf.dexlib2.iface.MethodImplementation;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
|
||||
@ -42,17 +41,14 @@ import java.util.List;
|
||||
public class InstructionOffsetMap {
|
||||
@Nonnull private final int[] instructionCodeOffsets;
|
||||
|
||||
public InstructionOffsetMap(@Nonnull MethodImplementation methodImpl) {
|
||||
List<? extends Instruction> instructions = methodImpl.getInstructions();
|
||||
int[] instructionCodeOffsets = new int[instructions.size()];
|
||||
public InstructionOffsetMap(@Nonnull List<? extends Instruction> instructions) {
|
||||
this.instructionCodeOffsets = new int[instructions.size()];
|
||||
|
||||
int codeOffset = 0;
|
||||
for (int i=0; i<instructions.size(); i++) {
|
||||
instructionCodeOffsets[i] = codeOffset;
|
||||
codeOffset += instructions.get(i).getCodeUnits();
|
||||
}
|
||||
|
||||
this.instructionCodeOffsets = instructionCodeOffsets;
|
||||
}
|
||||
|
||||
public int getInstructionIndexAtCodeOffset(int codeOffset) {
|
||||
|
@ -71,7 +71,7 @@ public class InstructionOffsetMapTest {
|
||||
/*25: 0x37*/ new ImmutableInstruction10t(Opcode.GOTO, 1)
|
||||
);
|
||||
ImmutableMethodImplementation impl = new ImmutableMethodImplementation(33, instructions, null, null);
|
||||
InstructionOffsetMap instructionOffsetMap = new InstructionOffsetMap(impl);
|
||||
InstructionOffsetMap instructionOffsetMap = new InstructionOffsetMap(instructions);
|
||||
|
||||
int[] expectedOffsets = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11,
|
||||
0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x37};
|
||||
|
Loading…
x
Reference in New Issue
Block a user