mirror of
https://github.com/revanced/smali.git
synced 2025-05-21 16:37:04 +02:00
smali/dexlib: deal with invoke-polymorphic / invoke-polymorphic/range.
- Introduces two new instruction formats, 45cc and 4rcc. As the name suggests, these instructions are similar to 35c and 3rc, expect that they encode an additional constant pool reference in their 4th byte. - Introduce two new instructions, invoke-polymorphic and invoke-polymorphic/range - used to implement signature polymorphism. - Allow instructions to directly reference the proto_id section of the dex file. This involves the introduction of a new kind of reference (MethodProtoReference) and has the side effect of cleaning up a fair amount of special casing in ProtoPool. - Disable support for ART version based switches (and remove LambdaTest which depends on it). Experimental lambda support and support for ART version based switches will be removed in a follow up change. Bug: 30550796 Test: test-art Test: ./gradlew build
This commit is contained in:
parent
a5d82813f1
commit
afc1f15939
@ -79,11 +79,20 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
return opcode.isVolatileFieldAccessor() || opcode == Opcode.THROW_VERIFICATION_ERROR;
|
||||
}
|
||||
|
||||
private String writeInvalidItemIndex(InvalidItemIndex ex, int type, IndentingWriter writer)
|
||||
throws IOException {
|
||||
writer.write("#");
|
||||
writer.write(ex.getMessage());
|
||||
writer.write("\n");
|
||||
return String.format("%s@%d", ReferenceType.toString(type), ex.getInvalidIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
String verificationErrorName = null;
|
||||
String referenceString = null;
|
||||
String referenceString2 = null;
|
||||
|
||||
boolean commentOutInstruction = false;
|
||||
|
||||
@ -100,25 +109,19 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
|
||||
if (instruction instanceof ReferenceInstruction) {
|
||||
ReferenceInstruction referenceInstruction = (ReferenceInstruction)instruction;
|
||||
try {
|
||||
Reference reference = referenceInstruction.getReference();
|
||||
|
||||
String classContext = null;
|
||||
if (methodDef.classDef.options.useImplicitReferences) {
|
||||
classContext = methodDef.method.getDefiningClass();
|
||||
}
|
||||
|
||||
try {
|
||||
Reference reference = referenceInstruction.getReference();
|
||||
referenceString = ReferenceUtil.getReferenceString(reference, classContext);
|
||||
assert referenceString != null;
|
||||
} catch (InvalidItemIndex ex) {
|
||||
writer.write("#");
|
||||
writer.write(ex.getMessage());
|
||||
writer.write("\n");
|
||||
commentOutInstruction = true;
|
||||
|
||||
referenceString = String.format("%s@%d",
|
||||
ReferenceType.toString(referenceInstruction.getReferenceType()),
|
||||
ex.getInvalidIndex());
|
||||
referenceString = writeInvalidItemIndex(ex, referenceInstruction.getReferenceType(),
|
||||
writer);
|
||||
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||
writer.write("#invalid reference type: ");
|
||||
writer.printSignedIntAsDec(ex.getReferenceType());
|
||||
@ -126,6 +129,25 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
|
||||
referenceString = "invalid_reference";
|
||||
}
|
||||
|
||||
if (instruction instanceof DualReferenceInstruction) {
|
||||
DualReferenceInstruction dualReferenceInstruction =
|
||||
(DualReferenceInstruction) instruction;
|
||||
try {
|
||||
Reference reference2 = dualReferenceInstruction.getReference2();
|
||||
referenceString2 = ReferenceUtil.getReferenceString(reference2, classContext);
|
||||
} catch (InvalidItemIndex ex) {
|
||||
commentOutInstruction = true;
|
||||
referenceString2 = writeInvalidItemIndex(ex,
|
||||
dualReferenceInstruction.getReferenceType2(), writer);
|
||||
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||
writer.write("#invalid reference type: ");
|
||||
writer.printSignedIntAsDec(ex.getReferenceType());
|
||||
commentOutInstruction = true;
|
||||
|
||||
referenceString2 = "invalid_reference";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instruction instanceof Instruction31t) {
|
||||
@ -355,6 +377,24 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
writer.write(", ");
|
||||
writeVtableIndex(writer);
|
||||
break;
|
||||
case Format45cc:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writer.write(referenceString);
|
||||
writer.write(", ");
|
||||
writer.write(referenceString2);
|
||||
break;
|
||||
case Format4rcc:
|
||||
writeOpcode(writer);
|
||||
writer.write(' ');
|
||||
writeInvokeRangeRegisters(writer);
|
||||
writer.write(", ");
|
||||
writer.write(referenceString);
|
||||
writer.write(", ");
|
||||
writer.write(referenceString2);
|
||||
break;
|
||||
default:
|
||||
assert false;
|
||||
return false;
|
||||
|
@ -63,6 +63,8 @@ public enum Format {
|
||||
Format3rc(6),
|
||||
Format3rmi(6),
|
||||
Format3rms(6),
|
||||
Format45cc(8),
|
||||
Format4rcc(8),
|
||||
Format51l(10),
|
||||
ArrayPayload(-1, true),
|
||||
PackedSwitchPayload(-1, true),
|
||||
|
@ -294,8 +294,8 @@ public enum Opcode
|
||||
|
||||
INVOKE_VIRTUAL_QUICK(combine(allApis(0xf8), allArtVersions(0xe9)), "invoke-virtual-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
INVOKE_VIRTUAL_QUICK_RANGE(combine(allApis(0xf9), allArtVersions(0xea)), "invoke-virtual-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
INVOKE_SUPER_QUICK(allApis(0xfa), "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
INVOKE_SUPER_QUICK_RANGE(allApis(0xfb), "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
INVOKE_SUPER_QUICK(lastApi(0xfa, 25), "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
INVOKE_SUPER_QUICK_RANGE(lastApi(0xfb, 25), "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
|
||||
IPUT_OBJECT_VOLATILE(firstApi(0xfc, 9), "iput-object-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
|
||||
SGET_OBJECT_VOLATILE(firstApi(0xfd, 9), "sget-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
|
||||
@ -313,7 +313,9 @@ public enum Opcode
|
||||
// TODO: do we need a capture/liberate wide?
|
||||
LIBERATE_VARIABLE(allArtVersions(0xf7), "liberate-variable", ReferenceType.STRING, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
|
||||
BOX_LAMBDA(allArtVersions(0xf8), "box-lambda", ReferenceType.NONE, Format.Format22x, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
|
||||
UNBOX_LAMBDA(allArtVersions(0xf9), "unbox-lambda", ReferenceType.TYPE, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL);
|
||||
UNBOX_LAMBDA(allArtVersions(0xf9), "unbox-lambda", ReferenceType.TYPE, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
|
||||
INVOKE_POLYMORPHIC(firstApi(0xfa, 26), "invoke-polymorphic", ReferenceType.METHOD, ReferenceType.METHOD_PROTO, Format.Format45cc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||
INVOKE_POLYMORPHIC_RANGE(firstApi(0xfb, 26), "invoke-polymorphic/range", ReferenceType.METHOD, ReferenceType.METHOD_PROTO, Format.Format4rcc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT);
|
||||
|
||||
//if the instruction can throw an exception
|
||||
public static final int CAN_THROW = 0x1;
|
||||
@ -359,6 +361,7 @@ public enum Opcode
|
||||
public final int referenceType;
|
||||
public final Format format;
|
||||
public final int flags;
|
||||
public final int referenceType2;
|
||||
|
||||
Opcode(int opcodeValue, String opcodeName, int referenceType, Format format) {
|
||||
this(opcodeValue, opcodeName, referenceType, format, 0);
|
||||
@ -369,6 +372,11 @@ public enum Opcode
|
||||
}
|
||||
|
||||
Opcode(List<VersionConstraint> versionConstraints, String opcodeName, int referenceType, Format format, int flags) {
|
||||
this(versionConstraints, opcodeName, referenceType, -1, format, flags);
|
||||
}
|
||||
|
||||
Opcode(List<VersionConstraint> versionConstraints, String opcodeName, int referenceType, int referenceType2,
|
||||
Format format, int flags) {
|
||||
ImmutableRangeMap.Builder<Integer, Short> apiToValueBuilder = ImmutableRangeMap.builder();
|
||||
ImmutableRangeMap.Builder<Integer, Short> artVersionToValueBuilder = ImmutableRangeMap.builder();
|
||||
|
||||
@ -385,6 +393,7 @@ public enum Opcode
|
||||
this.artVersionToValueMap = artVersionToValueBuilder.build();
|
||||
this.name = opcodeName;
|
||||
this.referenceType = referenceType;
|
||||
this.referenceType2 = referenceType2;
|
||||
this.format = format;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
@ -39,7 +39,8 @@ public final class ReferenceType {
|
||||
public static final int TYPE = 1;
|
||||
public static final int FIELD = 2;
|
||||
public static final int METHOD = 3;
|
||||
public static final int NONE = 4;
|
||||
public static final int METHOD_PROTO = 4;
|
||||
public static final int NONE = 5;
|
||||
|
||||
public static String toString(int referenceType) {
|
||||
switch (referenceType) {
|
||||
@ -51,6 +52,8 @@ public final class ReferenceType {
|
||||
return "field";
|
||||
case METHOD:
|
||||
return "method";
|
||||
case METHOD_PROTO:
|
||||
return "method_proto";
|
||||
default:
|
||||
throw new InvalidReferenceTypeException(referenceType);
|
||||
}
|
||||
@ -65,6 +68,8 @@ public final class ReferenceType {
|
||||
return FIELD;
|
||||
} else if (reference instanceof MethodReference) {
|
||||
return METHOD;
|
||||
} else if (reference instanceof MethodProtoReference) {
|
||||
return METHOD_PROTO;
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid reference");
|
||||
}
|
||||
@ -76,7 +81,7 @@ public final class ReferenceType {
|
||||
* @throws InvalidReferenceTypeException
|
||||
*/
|
||||
public static void validateReferenceType(int referenceType) {
|
||||
if (referenceType < 0 || referenceType > 3) {
|
||||
if (referenceType < 0 || referenceType > 4) {
|
||||
throw new InvalidReferenceTypeException(referenceType);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016, 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.base.reference;
|
||||
|
||||
import com.google.common.collect.Ordering;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.util.CharSequenceUtils;
|
||||
import org.jf.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
public abstract class BaseMethodProtoReference implements MethodProtoReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getReturnType().hashCode();
|
||||
return hashCode*31 + getParameterTypes().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o instanceof MethodProtoReference) {
|
||||
MethodProtoReference other = (MethodProtoReference)o;
|
||||
return getReturnType().equals(other.getReturnType()) &&
|
||||
CharSequenceUtils.listEquals(getParameterTypes(), other.getParameterTypes());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nonnull MethodProtoReference o) {
|
||||
int res = getReturnType().compareTo(o.getReturnType());
|
||||
if (res != 0) return res;
|
||||
return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes());
|
||||
}
|
||||
}
|
@ -60,7 +60,7 @@ public class BuilderInstruction35c extends BuilderInstruction implements Instruc
|
||||
int registerG,
|
||||
@Nonnull Reference reference) {
|
||||
super(opcode);
|
||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||
this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount);
|
||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||
this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0;
|
||||
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2016, 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.builder.instruction;
|
||||
|
||||
import org.jf.dexlib2.Format;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.builder.BuilderInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction45cc;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.dexlib2.util.Preconditions;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class BuilderInstruction45cc extends BuilderInstruction implements Instruction45cc {
|
||||
public static final Format FORMAT = Format.Format45cc;
|
||||
|
||||
protected final int registerCount;
|
||||
protected final int registerC;
|
||||
protected final int registerD;
|
||||
protected final int registerE;
|
||||
protected final int registerF;
|
||||
protected final int registerG;
|
||||
@Nonnull protected final Reference reference;
|
||||
@Nonnull protected final Reference reference2;
|
||||
|
||||
public BuilderInstruction45cc(@Nonnull Opcode opcode,
|
||||
int registerCount,
|
||||
int registerC,
|
||||
int registerD,
|
||||
int registerE,
|
||||
int registerF,
|
||||
int registerG,
|
||||
@Nonnull Reference reference,
|
||||
@Nonnull Reference reference2) {
|
||||
super(opcode);
|
||||
this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount);
|
||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||
this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0;
|
||||
this.registerF = (registerCount>3) ? Preconditions.checkNibbleRegister(registerF) : 0;
|
||||
this.registerG = (registerCount>4) ? Preconditions.checkNibbleRegister(registerG) : 0;
|
||||
this.reference = reference;
|
||||
this.reference2 = reference2;
|
||||
}
|
||||
|
||||
@Override public int getRegisterCount() { return registerCount; }
|
||||
@Override public int getRegisterC() { return registerC; }
|
||||
@Override public int getRegisterD() { return registerD; }
|
||||
@Override public int getRegisterE() { return registerE; }
|
||||
@Override public int getRegisterF() { return registerF; }
|
||||
@Override public int getRegisterG() { return registerG; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
@Nonnull @Override public Reference getReference2() { return reference2; }
|
||||
@Override public int getReferenceType2() { return opcode.referenceType2; }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.builder.instruction;
|
||||
|
||||
import org.jf.dexlib2.Format;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.builder.BuilderInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction4rcc;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.dexlib2.util.Preconditions;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class BuilderInstruction4rcc extends BuilderInstruction implements Instruction4rcc {
|
||||
public static final Format FORMAT = Format.Format4rcc;
|
||||
|
||||
protected final int startRegister;
|
||||
protected final int registerCount;
|
||||
|
||||
@Nonnull protected final Reference reference;
|
||||
@Nonnull protected final Reference reference2;
|
||||
|
||||
public BuilderInstruction4rcc(@Nonnull Opcode opcode,
|
||||
int startRegister,
|
||||
int registerCount,
|
||||
@Nonnull Reference reference,
|
||||
@Nonnull Reference reference2) {
|
||||
super(opcode);
|
||||
this.startRegister = Preconditions.checkShortRegister(startRegister);
|
||||
this.registerCount = Preconditions.checkRegisterRangeCount(registerCount);
|
||||
this.reference = reference;
|
||||
this.reference2 = reference2;
|
||||
}
|
||||
|
||||
@Override public int getStartRegister() { return startRegister; }
|
||||
@Override public int getRegisterCount() { return registerCount; }
|
||||
@Nonnull @Override public Reference getReference() { return reference; }
|
||||
@Override public int getReferenceType() { return opcode.referenceType; }
|
||||
@Nonnull @Override public Reference getReference2() { return reference2; }
|
||||
@Override public int getReferenceType2() { return opcode.referenceType2; }
|
||||
|
||||
@Override public Format getFormat() { return FORMAT; }
|
||||
}
|
@ -139,6 +139,10 @@ public abstract class DexBackedInstruction implements Instruction {
|
||||
return new DexBackedInstruction3rmi(dexFile, opcode, instructionStartOffset);
|
||||
case Format3rms:
|
||||
return new DexBackedInstruction3rms(dexFile, opcode, instructionStartOffset);
|
||||
case Format45cc:
|
||||
return new DexBackedInstruction45cc(dexFile, opcode, instructionStartOffset);
|
||||
case Format4rcc:
|
||||
return new DexBackedInstruction4rcc(dexFile, opcode, instructionStartOffset);
|
||||
case Format51l:
|
||||
return new DexBackedInstruction51l(dexFile, opcode, instructionStartOffset);
|
||||
case PackedSwitchPayload:
|
||||
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2016, 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.instruction;
|
||||
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.dexbacked.reference.DexBackedReference;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction45cc;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.util.NibbleUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class DexBackedInstruction45cc extends DexBackedInstruction implements Instruction45cc {
|
||||
public DexBackedInstruction45cc(@Nonnull DexBackedDexFile dexFile,
|
||||
@Nonnull Opcode opcode,
|
||||
int instructionStart) {
|
||||
super(dexFile, opcode, instructionStart);
|
||||
}
|
||||
|
||||
@Override public int getRegisterCount() {
|
||||
return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegisterC() {
|
||||
return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegisterD() {
|
||||
return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegisterE() {
|
||||
return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 5));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegisterF() {
|
||||
return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 5));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegisterG() {
|
||||
return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 1));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Reference getReference() {
|
||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
||||
dexFile.readUshort(instructionStart + 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReferenceType() {
|
||||
return opcode.referenceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reference getReference2() {
|
||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType2,
|
||||
dexFile.readUshort(instructionStart + 3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReferenceType2() {
|
||||
return opcode.referenceType2;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2016, 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.instruction;
|
||||
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.dexbacked.reference.DexBackedReference;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction4rcc;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class DexBackedInstruction4rcc extends DexBackedInstruction implements Instruction4rcc {
|
||||
public DexBackedInstruction4rcc(@Nonnull DexBackedDexFile dexFile,
|
||||
@Nonnull Opcode opcode,
|
||||
int instructionStart) {
|
||||
super(dexFile, opcode, instructionStart);
|
||||
}
|
||||
|
||||
@Override public int getRegisterCount() {
|
||||
return dexFile.readUbyte(instructionStart + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartRegister() {
|
||||
return dexFile.readUshort(instructionStart + 4);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Reference getReference() {
|
||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType,
|
||||
dexFile.readUshort(instructionStart + 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReferenceType() {
|
||||
return opcode.referenceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reference getReference2() {
|
||||
return DexBackedReference.makeReference(dexFile, opcode.referenceType2,
|
||||
dexFile.readUshort(instructionStart + 3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReferenceType2() {
|
||||
return opcode.referenceType2;
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2016, 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.reference;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.jf.dexlib2.base.reference.BaseMethodProtoReference;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.dexbacked.raw.ProtoIdItem;
|
||||
import org.jf.dexlib2.dexbacked.raw.TypeListItem;
|
||||
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
|
||||
@Nonnull public final DexBackedDexFile dexFile;
|
||||
private final int protoIdItemOffset;
|
||||
|
||||
public DexBackedMethodProtoReference(@Nonnull DexBackedDexFile dexFile, int protoIndex) {
|
||||
this.dexFile = dexFile;
|
||||
this.protoIdItemOffset = dexFile.getProtoIdItemOffset(protoIndex);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<String> getParameterTypes() {
|
||||
final int parametersOffset = dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.PARAMETERS_OFFSET);
|
||||
if (parametersOffset > 0) {
|
||||
final int parameterCount = dexFile.readSmallUint(parametersOffset + TypeListItem.SIZE_OFFSET);
|
||||
final int paramListStart = parametersOffset + TypeListItem.LIST_OFFSET;
|
||||
return new FixedSizeList<String>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String readItem(final int index) {
|
||||
return dexFile.getType(dexFile.readUshort(paramListStart + 2*index));
|
||||
}
|
||||
@Override public int size() { return parameterCount; }
|
||||
};
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return dexFile.getType(dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.RETURN_TYPE_OFFSET));
|
||||
}
|
||||
}
|
@ -49,6 +49,8 @@ public abstract class DexBackedReference {
|
||||
return new DexBackedMethodReference(dexFile, referenceIndex);
|
||||
case ReferenceType.FIELD:
|
||||
return new DexBackedFieldReference(dexFile, referenceIndex);
|
||||
case ReferenceType.METHOD_PROTO:
|
||||
return new DexBackedMethodProtoReference(dexFile, referenceIndex);
|
||||
default:
|
||||
throw new ExceptionWithContext("Invalid reference type: %d", referenceType);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015, Google Inc.
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,21 +29,13 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.baksmali;
|
||||
package org.jf.dexlib2.iface.instruction;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
|
||||
public class LambdaTest extends IdenticalRoundtripTest {
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
private baksmaliOptions createOptions() {
|
||||
baksmaliOptions options = new baksmaliOptions();
|
||||
options.apiLevel = 23; // since we need at least level 23 for lambda opcodes
|
||||
options.experimental = true; // since these opcodes aren't implemented in runtime yet);
|
||||
return options;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelloWorldLambda() {
|
||||
runTest("HelloWorldLambda", createOptions());
|
||||
}
|
||||
public interface DualReferenceInstruction extends ReferenceInstruction {
|
||||
@Nonnull Reference getReference2();
|
||||
int getReferenceType2();
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2016, 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.iface.instruction.formats;
|
||||
|
||||
import org.jf.dexlib2.iface.instruction.DualReferenceInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction;
|
||||
|
||||
public interface Instruction45cc extends FiveRegisterInstruction, DualReferenceInstruction {
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2016, 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.iface.instruction.formats;
|
||||
|
||||
import org.jf.dexlib2.iface.instruction.DualReferenceInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.RegisterRangeInstruction;
|
||||
|
||||
public interface Instruction4rcc extends RegisterRangeInstruction, DualReferenceInstruction {
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 20116, 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.iface.reference;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a reference to a method prototype.
|
||||
*/
|
||||
public interface MethodProtoReference extends Reference, Comparable<MethodProtoReference> {
|
||||
/**
|
||||
* Gets a list of the types of the parameters of this method prototype.
|
||||
*
|
||||
* @return A list of the parameter types of this method prototype, as strings.
|
||||
*/
|
||||
@Nonnull List<? extends CharSequence> getParameterTypes();
|
||||
|
||||
/**
|
||||
* Gets the return type of the referenced method prototype.
|
||||
*
|
||||
* @return The return type of the referenced method prototype.
|
||||
*/
|
||||
@Nonnull String getReturnType();
|
||||
|
||||
/**
|
||||
* Returns a hashcode for this MethodProtoReference.
|
||||
*
|
||||
* This hashCode is defined to be the following:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* int hashCode = getReturnType().hashCode();
|
||||
* hashCode = hashCode*31 + CharSequenceUtils.listHashCode(getParameters());
|
||||
* }</pre>
|
||||
*
|
||||
* @return The hash code value for this ProtoReference
|
||||
*/
|
||||
@Override int hashCode();
|
||||
|
||||
/**
|
||||
* Compares this MethodTypeReference to another MethodProtoReference for equality.
|
||||
*
|
||||
* This MethodTypeReference is equal to another MethodProtoReference if all of it's "fields" are equal. That is, if
|
||||
* the return values of getReturnType() and getParameterTypes() are all equal.
|
||||
*
|
||||
* Equality for getParameters() should be tested by comparing the string representation of each element. I.e.
|
||||
* CharSequenceUtils.listEquals(this.getParameterTypes(), other.getParameterTypes())
|
||||
*
|
||||
* @param o The object to be compared for equality with this MethodProtoReference
|
||||
* @return true if the specified object is equal to this MethodProtoReference
|
||||
*/
|
||||
@Override boolean equals(@Nullable Object o);
|
||||
|
||||
/**
|
||||
* Compare this MethodTypeReference to another MethodProtoReference.
|
||||
*
|
||||
* The comparison is based on the comparison of the return values of getReturnType() and getParameters(),
|
||||
* in that order. getParameters() should be compared using the semantics of
|
||||
* org.jf.util.CollectionUtils.compareAsList()
|
||||
*
|
||||
* @param o The MethodReference to compare with this MethodProtoReference
|
||||
* @return An integer representing the result of the comparison
|
||||
*/
|
||||
@Override int compareTo(@Nonnull MethodProtoReference o);
|
||||
}
|
@ -61,7 +61,7 @@ public class ImmutableInstruction35c extends ImmutableInstruction implements Ins
|
||||
int registerG,
|
||||
@Nonnull Reference reference) {
|
||||
super(opcode);
|
||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||
this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount);
|
||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||
this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0;
|
||||
|
@ -58,7 +58,7 @@ public class ImmutableInstruction35mi extends ImmutableInstruction implements In
|
||||
int registerG,
|
||||
int inlineIndex) {
|
||||
super(opcode);
|
||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||
this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount);
|
||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||
this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0;
|
||||
|
@ -58,7 +58,7 @@ public class ImmutableInstruction35ms extends ImmutableInstruction implements In
|
||||
int registerG,
|
||||
int vtableIndex) {
|
||||
super(opcode);
|
||||
this.registerCount = Preconditions.check35cRegisterCount(registerCount);
|
||||
this.registerCount = Preconditions.check35cAnd45ccRegisterCount(registerCount);
|
||||
this.registerC = (registerCount>0) ? Preconditions.checkNibbleRegister(registerC) : 0;
|
||||
this.registerD = (registerCount>1) ? Preconditions.checkNibbleRegister(registerD) : 0;
|
||||
this.registerE = (registerCount>2) ? Preconditions.checkNibbleRegister(registerE) : 0;
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2016, 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.immutable.reference;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.jf.dexlib2.base.reference.BaseMethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.immutable.util.CharSequenceConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ImmutableMethodProtoReference extends BaseMethodProtoReference implements ImmutableReference {
|
||||
@Nonnull protected final ImmutableList<String> parameters;
|
||||
@Nonnull protected final String returnType;
|
||||
|
||||
public ImmutableMethodProtoReference(@Nullable Iterable<? extends CharSequence> parameters,
|
||||
@Nonnull String returnType) {
|
||||
this.parameters = CharSequenceConverter.immutableStringList(parameters);
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@Nonnull public static ImmutableMethodProtoReference of(@Nonnull MethodProtoReference methodProtoReference) {
|
||||
if (methodProtoReference instanceof ImmutableMethodProtoReference) {
|
||||
return (ImmutableMethodProtoReference) methodProtoReference;
|
||||
}
|
||||
return new ImmutableMethodProtoReference(
|
||||
methodProtoReference.getParameterTypes(),
|
||||
methodProtoReference.getReturnType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends CharSequence> getParameterTypes() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
}
|
@ -52,6 +52,9 @@ public class ImmutableReferenceFactory {
|
||||
if (reference instanceof MethodReference) {
|
||||
return ImmutableMethodReference.of((MethodReference)reference);
|
||||
}
|
||||
if (reference instanceof MethodProtoReference) {
|
||||
return ImmutableMethodProtoReference.of((MethodProtoReference) reference);
|
||||
}
|
||||
throw new ExceptionWithContext("Invalid reference type");
|
||||
}
|
||||
|
||||
@ -66,6 +69,8 @@ public class ImmutableReferenceFactory {
|
||||
return ImmutableFieldReference.of((FieldReference)reference);
|
||||
case ReferenceType.METHOD:
|
||||
return ImmutableMethodReference.of((MethodReference)reference);
|
||||
case ReferenceType.METHOD_PROTO:
|
||||
return ImmutableMethodProtoReference.of((MethodProtoReference)reference);
|
||||
}
|
||||
throw new ExceptionWithContext("Invalid reference type: %d", referenceType);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class Preconditions {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static int check35cRegisterCount(int registerCount) {
|
||||
public static int check35cAnd45ccRegisterCount(int registerCount) {
|
||||
if (registerCount < 0 || registerCount > 5) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid register count: %d. Must be between 0 and 5, inclusive.", registerCount));
|
||||
|
@ -60,6 +60,17 @@ public final class ReferenceUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getMethodProtoDescriptor(MethodProtoReference methodProtoReference) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
for (CharSequence paramType : methodProtoReference.getParameterTypes()) {
|
||||
sb.append(paramType);
|
||||
}
|
||||
sb.append(')');
|
||||
sb.append(methodProtoReference.getReturnType());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void writeMethodDescriptor(Writer writer, MethodReference methodReference) throws IOException {
|
||||
writeMethodDescriptor(writer, methodReference, false);
|
||||
}
|
||||
@ -134,12 +145,16 @@ public final class ReferenceUtil {
|
||||
if (reference instanceof FieldReference) {
|
||||
FieldReference fieldReference = (FieldReference)reference;
|
||||
boolean useImplicitReference = fieldReference.getDefiningClass().equals(containingClass);
|
||||
return getFieldDescriptor((FieldReference)reference, useImplicitReference);
|
||||
return getFieldDescriptor(fieldReference, useImplicitReference);
|
||||
}
|
||||
if (reference instanceof MethodReference) {
|
||||
MethodReference methodReference = (MethodReference)reference;
|
||||
boolean useImplicitReference = methodReference.getDefiningClass().equals(containingClass);
|
||||
return getMethodDescriptor((MethodReference)reference, useImplicitReference);
|
||||
return getMethodDescriptor(methodReference, useImplicitReference);
|
||||
}
|
||||
if (reference instanceof MethodProtoReference) {
|
||||
MethodProtoReference methodProtoReference = (MethodProtoReference)reference;
|
||||
return getMethodProtoDescriptor(methodProtoReference);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.*;
|
||||
import org.jf.dexlib2.iface.reference.FieldReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
import org.jf.dexlib2.iface.reference.StringReference;
|
||||
import org.jf.dexlib2.iface.reference.TypeReference;
|
||||
@ -84,7 +85,7 @@ import java.util.zip.Adler32;
|
||||
|
||||
public abstract class DexWriter<
|
||||
StringKey extends CharSequence, StringRef extends StringReference, TypeKey extends CharSequence,
|
||||
TypeRef extends TypeReference, ProtoKey extends Comparable<ProtoKey>,
|
||||
TypeRef extends TypeReference, ProtoRefKey extends MethodProtoReference,
|
||||
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
|
||||
ClassKey extends Comparable<? super ClassKey>,
|
||||
AnnotationKey extends Annotation, AnnotationSetKey,
|
||||
@ -125,9 +126,9 @@ public abstract class DexWriter<
|
||||
|
||||
protected final StringSection<StringKey, StringRef> stringSection;
|
||||
protected final TypeSection<StringKey, TypeKey, TypeRef> typeSection;
|
||||
protected final ProtoSection<StringKey, TypeKey, ProtoKey, TypeListKey> protoSection;
|
||||
protected final ProtoSection<StringKey, TypeKey, ProtoRefKey, TypeListKey> protoSection;
|
||||
protected final FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey> fieldSection;
|
||||
protected final MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey, MethodKey> methodSection;
|
||||
protected final MethodSection<StringKey, TypeKey, ProtoRefKey, MethodRefKey, MethodKey> methodSection;
|
||||
protected final ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey, AnnotationSetKey,
|
||||
EncodedValue> classSection;
|
||||
|
||||
@ -138,9 +139,9 @@ public abstract class DexWriter<
|
||||
protected DexWriter(Opcodes opcodes,
|
||||
StringSection<StringKey, StringRef> stringSection,
|
||||
TypeSection<StringKey, TypeKey, TypeRef> typeSection,
|
||||
ProtoSection<StringKey, TypeKey, ProtoKey, TypeListKey> protoSection,
|
||||
ProtoSection<StringKey, TypeKey, ProtoRefKey, TypeListKey> protoSection,
|
||||
FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey> fieldSection,
|
||||
MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey, MethodKey> methodSection,
|
||||
MethodSection<StringKey, TypeKey, ProtoRefKey, MethodRefKey, MethodKey> methodSection,
|
||||
ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey, AnnotationSetKey,
|
||||
EncodedValue> classSection,
|
||||
TypeListSection<TypeKey, TypeListKey> typeListSection,
|
||||
@ -347,12 +348,12 @@ public abstract class DexWriter<
|
||||
protoSectionOffset = writer.getPosition();
|
||||
int index = 0;
|
||||
|
||||
List<Map.Entry<? extends ProtoKey, Integer>> protoEntries = Lists.newArrayList(protoSection.getItems());
|
||||
Collections.sort(protoEntries, DexWriter.<ProtoKey>comparableKeyComparator());
|
||||
List<Map.Entry<? extends ProtoRefKey, Integer>> protoEntries = Lists.newArrayList(protoSection.getItems());
|
||||
Collections.sort(protoEntries, DexWriter.<ProtoRefKey>comparableKeyComparator());
|
||||
|
||||
for (Map.Entry<? extends ProtoKey, Integer> entry: protoEntries) {
|
||||
for (Map.Entry<? extends ProtoRefKey, Integer> entry: protoEntries) {
|
||||
entry.setValue(index++);
|
||||
ProtoKey key = entry.getKey();
|
||||
ProtoRefKey key = entry.getKey();
|
||||
writer.writeInt(stringSection.getItemIndex(protoSection.getShorty(key)));
|
||||
writer.writeInt(typeSection.getItemIndex(protoSection.getReturnType(key)));
|
||||
writer.writeInt(typeListSection.getNullableItemOffset(protoSection.getParameters(key)));
|
||||
@ -946,7 +947,7 @@ public abstract class DexWriter<
|
||||
|
||||
InstructionWriter instructionWriter =
|
||||
InstructionWriter.makeInstructionWriter(opcodes, writer, stringSection, typeSection, fieldSection,
|
||||
methodSection);
|
||||
methodSection, protoSection);
|
||||
|
||||
writer.writeInt(codeUnitCount);
|
||||
for (Instruction instruction: instructions) {
|
||||
@ -1029,6 +1030,12 @@ public abstract class DexWriter<
|
||||
case Format3rc:
|
||||
instructionWriter.write((Instruction3rc)instruction);
|
||||
break;
|
||||
case Format45cc:
|
||||
instructionWriter.write((Instruction45cc) instruction);
|
||||
break;
|
||||
case Format4rcc:
|
||||
instructionWriter.write((Instruction4rcc) instruction);
|
||||
break;
|
||||
case Format51l:
|
||||
instructionWriter.write((Instruction51l)instruction);
|
||||
break;
|
||||
|
@ -36,11 +36,14 @@ import com.google.common.primitives.Ints;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.Opcodes;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.iface.instruction.DualReferenceInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||
import org.jf.dexlib2.iface.instruction.formats.*;
|
||||
import org.jf.dexlib2.iface.reference.FieldReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.dexlib2.iface.reference.StringReference;
|
||||
import org.jf.dexlib2.iface.reference.TypeReference;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
@ -51,25 +54,29 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class InstructionWriter<StringRef extends StringReference, TypeRef extends TypeReference,
|
||||
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference> {
|
||||
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
|
||||
ProtoRefKey extends MethodProtoReference> {
|
||||
@Nonnull private final Opcodes opcodes;
|
||||
@Nonnull private final DexDataWriter writer;
|
||||
@Nonnull private final StringSection<?, StringRef> stringSection;
|
||||
@Nonnull private final TypeSection<?, ?, TypeRef> typeSection;
|
||||
@Nonnull private final FieldSection<?, ?, FieldRefKey, ?> fieldSection;
|
||||
@Nonnull private final MethodSection<?, ?, ?, MethodRefKey, ?> methodSection;
|
||||
@Nonnull private final ProtoSection<?, ?, ProtoRefKey, ?> protoSection;
|
||||
|
||||
@Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference, FieldRefKey extends FieldReference, MethodRefKey extends MethodReference>
|
||||
InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey>
|
||||
@Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference, FieldRefKey extends FieldReference,
|
||||
MethodRefKey extends MethodReference, ProtoRefKey extends MethodProtoReference>
|
||||
InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey>
|
||||
makeInstructionWriter(
|
||||
@Nonnull Opcodes opcodes,
|
||||
@Nonnull DexDataWriter writer,
|
||||
@Nonnull StringSection<?, StringRef> stringSection,
|
||||
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
|
||||
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
|
||||
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection) {
|
||||
return new InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey>(
|
||||
opcodes, writer, stringSection, typeSection, fieldSection, methodSection);
|
||||
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
|
||||
@Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection) {
|
||||
return new InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey>(
|
||||
opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection);
|
||||
}
|
||||
|
||||
InstructionWriter(@Nonnull Opcodes opcodes,
|
||||
@ -77,13 +84,15 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
|
||||
@Nonnull StringSection<?, StringRef> stringSection,
|
||||
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
|
||||
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
|
||||
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection) {
|
||||
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
|
||||
@Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection) {
|
||||
this.opcodes = opcodes;
|
||||
this.writer = writer;
|
||||
this.stringSection = stringSection;
|
||||
this.typeSection = typeSection;
|
||||
this.fieldSection = fieldSection;
|
||||
this.methodSection = methodSection;
|
||||
this.protoSection = protoSection;
|
||||
}
|
||||
|
||||
private short getOpcodeValue(Opcode opcode) {
|
||||
@ -347,6 +356,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(@Nonnull Instruction3rc instruction) {
|
||||
try {
|
||||
writer.write(getOpcodeValue(instruction.getOpcode()));
|
||||
@ -358,6 +368,31 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
|
||||
}
|
||||
}
|
||||
|
||||
public void write(@Nonnull Instruction45cc instruction) {
|
||||
try {
|
||||
writer.write(getOpcodeValue(instruction.getOpcode()));
|
||||
writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
|
||||
writer.writeUshort(getReferenceIndex(instruction));
|
||||
writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
|
||||
writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
|
||||
writer.writeUshort(getReference2Index(instruction));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(@Nonnull Instruction4rcc instruction) {
|
||||
try {
|
||||
writer.write(getOpcodeValue(instruction.getOpcode()));
|
||||
writer.write(instruction.getRegisterCount());
|
||||
writer.writeUshort(getReferenceIndex(instruction));
|
||||
writer.writeUshort(instruction.getStartRegister());
|
||||
writer.writeUshort(getReference2Index(instruction));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(@Nonnull Instruction51l instruction) {
|
||||
try {
|
||||
writer.write(getOpcodeValue(instruction.getOpcode()));
|
||||
@ -452,18 +487,29 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
|
||||
}
|
||||
|
||||
private int getReferenceIndex(ReferenceInstruction referenceInstruction) {
|
||||
switch (referenceInstruction.getOpcode().referenceType) {
|
||||
return getReferenceIndex(referenceInstruction.getReferenceType(),
|
||||
referenceInstruction.getReference());
|
||||
}
|
||||
|
||||
private int getReference2Index(DualReferenceInstruction referenceInstruction) {
|
||||
return getReferenceIndex(referenceInstruction.getReferenceType2(),
|
||||
referenceInstruction.getReference2());
|
||||
}
|
||||
|
||||
private int getReferenceIndex(int referenceType, Reference reference) {
|
||||
switch (referenceType) {
|
||||
case ReferenceType.FIELD:
|
||||
return fieldSection.getItemIndex((FieldRefKey)referenceInstruction.getReference());
|
||||
return fieldSection.getItemIndex((FieldRefKey) reference);
|
||||
case ReferenceType.METHOD:
|
||||
return methodSection.getItemIndex((MethodRefKey)referenceInstruction.getReference());
|
||||
return methodSection.getItemIndex((MethodRefKey) reference);
|
||||
case ReferenceType.STRING:
|
||||
return stringSection.getItemIndex((StringRef)referenceInstruction.getReference());
|
||||
return stringSection.getItemIndex((StringRef) reference);
|
||||
case ReferenceType.TYPE:
|
||||
return typeSection.getItemIndex((TypeRef)referenceInstruction.getReference());
|
||||
return typeSection.getItemIndex((TypeRef) reference);
|
||||
case ReferenceType.METHOD_PROTO:
|
||||
return protoSection.getItemIndex((ProtoRefKey) reference);
|
||||
default:
|
||||
throw new ExceptionWithContext("Unknown reference type: %d",
|
||||
referenceInstruction.getOpcode().referenceType);
|
||||
throw new ExceptionWithContext("Unknown reference type: %d", referenceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,15 +31,17 @@
|
||||
|
||||
package org.jf.dexlib2.writer;
|
||||
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public interface MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey extends MethodReference, MethodKey>
|
||||
public interface MethodSection<StringKey, TypeKey, ProtoRefKey extends MethodProtoReference,
|
||||
MethodRefKey extends MethodReference, MethodKey>
|
||||
extends IndexSection<MethodRefKey> {
|
||||
@Nonnull TypeKey getDefiningClass(@Nonnull MethodRefKey key);
|
||||
@Nonnull ProtoKey getPrototype(@Nonnull MethodRefKey key);
|
||||
@Nonnull ProtoKey getPrototype(@Nonnull MethodKey key);
|
||||
@Nonnull ProtoRefKey getPrototype(@Nonnull MethodRefKey key);
|
||||
@Nonnull ProtoRefKey getPrototype(@Nonnull MethodKey key);
|
||||
@Nonnull StringKey getName(@Nonnull MethodRefKey key);
|
||||
int getMethodIndex(@Nonnull MethodKey key);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
class BuilderMethodPool implements MethodSection<BuilderStringReference, BuilderTypeReference,
|
||||
BuilderProtoReference, BuilderMethodReference, BuilderMethod>{
|
||||
BuilderMethodProtoReference, BuilderMethodReference, BuilderMethod>{
|
||||
@Nonnull private final BuilderContext context;
|
||||
@Nonnull private final ConcurrentMap<MethodReference, BuilderMethodReference> internedItems =
|
||||
Maps.newConcurrentMap();
|
||||
@ -61,7 +61,7 @@ class BuilderMethodPool implements MethodSection<BuilderStringReference, Builder
|
||||
BuilderMethodReference dexPoolMethodReference = new BuilderMethodReference(
|
||||
context.typePool.internType(methodReference.getDefiningClass()),
|
||||
context.stringPool.internString(methodReference.getName()),
|
||||
context.protoPool.internProto(methodReference));
|
||||
context.protoPool.internMethodProto(methodReference));
|
||||
ret = internedItems.putIfAbsent(dexPoolMethodReference, dexPoolMethodReference);
|
||||
return ret==null?dexPoolMethodReference:ret;
|
||||
}
|
||||
@ -78,11 +78,11 @@ class BuilderMethodPool implements MethodSection<BuilderStringReference, Builder
|
||||
}
|
||||
|
||||
@Nonnull @Override
|
||||
public BuilderProtoReference getPrototype(@Nonnull BuilderMethodReference key) {
|
||||
public BuilderMethodProtoReference getPrototype(@Nonnull BuilderMethodReference key) {
|
||||
return key.proto;
|
||||
}
|
||||
|
||||
@Nonnull @Override public BuilderProtoReference getPrototype(@Nonnull BuilderMethod builderMethod) {
|
||||
@Nonnull @Override public BuilderMethodProtoReference getPrototype(@Nonnull BuilderMethod builderMethod) {
|
||||
return builderMethod.methodReference.proto;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
||||
package org.jf.dexlib2.writer.builder;
|
||||
|
||||
import com.google.common.collect.Ordering;
|
||||
import org.jf.dexlib2.base.reference.BaseMethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.writer.DexWriter;
|
||||
import org.jf.util.CharSequenceUtils;
|
||||
import org.jf.util.CollectionUtils;
|
||||
@ -40,13 +42,14 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class BuilderProtoReference implements BuilderProtoPool.ProtoKey, Comparable<BuilderProtoReference> {
|
||||
public class BuilderMethodProtoReference extends BaseMethodProtoReference implements
|
||||
MethodProtoReference, BuilderReference {
|
||||
@Nonnull final BuilderStringReference shorty;
|
||||
@Nonnull final BuilderTypeList parameterTypes;
|
||||
@Nonnull final BuilderTypeReference returnType;
|
||||
int index = DexWriter.NO_INDEX;
|
||||
|
||||
public BuilderProtoReference(@Nonnull BuilderStringReference shorty, @Nonnull BuilderTypeList parameterTypes,
|
||||
public BuilderMethodProtoReference(@Nonnull BuilderStringReference shorty, @Nonnull BuilderTypeList parameterTypes,
|
||||
@Nonnull BuilderTypeReference returnType) {
|
||||
this.shorty = shorty;
|
||||
this.parameterTypes = parameterTypes;
|
||||
@ -62,25 +65,12 @@ public class BuilderProtoReference implements BuilderProtoPool.ProtoKey, Compara
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getReturnType().hashCode();
|
||||
return hashCode*31 + getParameterTypes().hashCode();
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o != null && o instanceof BuilderProtoReference) {
|
||||
BuilderProtoReference other = (BuilderProtoReference)o;
|
||||
return returnType.equals(other.returnType) &&
|
||||
CharSequenceUtils.listEquals(parameterTypes, other.parameterTypes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nonnull BuilderProtoReference o) {
|
||||
int res = returnType.compareTo(o.returnType);
|
||||
if (res != 0) return res;
|
||||
return CollectionUtils.compareAsIterable(Ordering.usingToString(), parameterTypes, o.parameterTypes);
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
}
|
@ -39,12 +39,12 @@ import javax.annotation.Nonnull;
|
||||
public class BuilderMethodReference extends BaseMethodReference implements BuilderReference {
|
||||
@Nonnull final BuilderTypeReference definingClass;
|
||||
@Nonnull final BuilderStringReference name;
|
||||
@Nonnull final BuilderProtoReference proto;
|
||||
@Nonnull final BuilderMethodProtoReference proto;
|
||||
int index = DexWriter.NO_INDEX;
|
||||
|
||||
BuilderMethodReference(@Nonnull BuilderTypeReference definingClass,
|
||||
@Nonnull BuilderStringReference name,
|
||||
@Nonnull BuilderProtoReference proto) {
|
||||
@Nonnull BuilderMethodProtoReference proto) {
|
||||
this.definingClass = definingClass;
|
||||
this.name = name;
|
||||
this.proto = proto;
|
||||
|
@ -32,114 +32,75 @@
|
||||
package org.jf.dexlib2.writer.builder;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodProtoReference;
|
||||
import org.jf.dexlib2.util.MethodUtil;
|
||||
import org.jf.dexlib2.writer.ProtoSection;
|
||||
import org.jf.util.CharSequenceUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
class BuilderProtoPool
|
||||
implements ProtoSection<BuilderStringReference, BuilderTypeReference, BuilderProtoReference, BuilderTypeList> {
|
||||
implements ProtoSection<BuilderStringReference, BuilderTypeReference, BuilderMethodProtoReference, BuilderTypeList> {
|
||||
@Nonnull private final BuilderContext context;
|
||||
@Nonnull private final ConcurrentMap<ProtoKey, BuilderProtoReference> internedItems =
|
||||
@Nonnull private final ConcurrentMap<MethodProtoReference, BuilderMethodProtoReference> internedItems =
|
||||
Maps.newConcurrentMap();
|
||||
|
||||
BuilderProtoPool(@Nonnull BuilderContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Nonnull public BuilderProtoReference internProto(@Nonnull List<? extends CharSequence> parameters,
|
||||
@Nonnull String returnType) {
|
||||
ProtoKey key = new Key(parameters, returnType);
|
||||
BuilderProtoReference ret = internedItems.get(key);
|
||||
@Nonnull public BuilderMethodProtoReference internMethodProto(@Nonnull MethodProtoReference methodProto) {
|
||||
BuilderMethodProtoReference ret = internedItems.get(methodProto);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
BuilderProtoReference protoReference = new BuilderProtoReference(
|
||||
context.stringPool.internString(MethodUtil.getShorty(parameters, returnType)),
|
||||
context.typeListPool.internTypeList(parameters),
|
||||
context.typePool.internType(returnType));
|
||||
BuilderMethodProtoReference protoReference = new BuilderMethodProtoReference(
|
||||
context.stringPool.internString(MethodUtil.getShorty(
|
||||
methodProto.getParameterTypes(), methodProto.getReturnType())),
|
||||
context.typeListPool.internTypeList(methodProto.getParameterTypes()),
|
||||
context.typePool.internType(methodProto.getReturnType()));
|
||||
ret = internedItems.putIfAbsent(protoReference, protoReference);
|
||||
return ret==null?protoReference:ret;
|
||||
}
|
||||
|
||||
@Nonnull public BuilderProtoReference internProto(@Nonnull MethodReference methodReference) {
|
||||
return internProto(methodReference.getParameterTypes(), methodReference.getReturnType());
|
||||
@Nonnull public BuilderMethodProtoReference internMethodProto(@Nonnull MethodReference methodReference) {
|
||||
return internMethodProto(new ImmutableMethodProtoReference(
|
||||
methodReference.getParameterTypes(), methodReference.getReturnType()));
|
||||
}
|
||||
|
||||
@Nonnull @Override public BuilderStringReference getShorty(@Nonnull BuilderProtoReference key) {
|
||||
return key.shorty;
|
||||
@Nonnull @Override public BuilderStringReference getShorty(@Nonnull BuilderMethodProtoReference proto) {
|
||||
return proto.shorty;
|
||||
}
|
||||
|
||||
@Nonnull @Override public BuilderTypeReference getReturnType(@Nonnull BuilderProtoReference key) {
|
||||
return key.returnType;
|
||||
@Nonnull @Override public BuilderTypeReference getReturnType(@Nonnull BuilderMethodProtoReference proto) {
|
||||
return proto.returnType;
|
||||
}
|
||||
|
||||
@Nullable @Override public BuilderTypeList getParameters(@Nonnull BuilderProtoReference key) {
|
||||
return key.parameterTypes;
|
||||
@Nullable @Override public BuilderTypeList getParameters(@Nonnull BuilderMethodProtoReference proto) {
|
||||
return proto.parameterTypes;
|
||||
}
|
||||
|
||||
@Override public int getItemIndex(@Nonnull BuilderProtoReference key) {
|
||||
@Override public int getItemIndex(@Nonnull BuilderMethodProtoReference proto) {
|
||||
return proto.getIndex();
|
||||
}
|
||||
|
||||
@Nonnull @Override public Collection<? extends Entry<? extends BuilderMethodProtoReference, Integer>> getItems() {
|
||||
return new BuilderMapEntryCollection<BuilderMethodProtoReference>(internedItems.values()) {
|
||||
@Override protected int getValue(@Nonnull BuilderMethodProtoReference key) {
|
||||
return key.index;
|
||||
}
|
||||
|
||||
@Nonnull @Override public Collection<? extends Entry<? extends BuilderProtoReference, Integer>> getItems() {
|
||||
return new BuilderMapEntryCollection<BuilderProtoReference>(internedItems.values()) {
|
||||
@Override protected int getValue(@Nonnull BuilderProtoReference key) {
|
||||
return key.index;
|
||||
}
|
||||
|
||||
@Override protected int setValue(@Nonnull BuilderProtoReference key, int value) {
|
||||
@Override protected int setValue(@Nonnull BuilderMethodProtoReference key, int value) {
|
||||
int prev = key.index;
|
||||
key.index = value;
|
||||
return prev;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// a placeholder interface to unify the temporary probing key and the BuilderProtoReference class
|
||||
interface ProtoKey {
|
||||
@Nonnull List<? extends CharSequence> getParameterTypes();
|
||||
@Nonnull String getReturnType();
|
||||
}
|
||||
|
||||
// a temporary lightweight class to allow a quick probe if the given prototype has already been interned
|
||||
private static class Key implements ProtoKey {
|
||||
@Nonnull private final List<? extends CharSequence> parameters;
|
||||
@Nonnull private final String returnType;
|
||||
|
||||
public Key(@Nonnull List<? extends CharSequence> parameters, @Nonnull String returnType) {
|
||||
this.parameters = parameters;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@Nonnull public List<? extends CharSequence> getParameterTypes() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Nonnull public String getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
int hashCode = returnType.hashCode();
|
||||
return hashCode*31 + parameters.hashCode();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
if (o != null && o instanceof ProtoKey) {
|
||||
ProtoKey other = (ProtoKey)o;
|
||||
return getReturnType().equals(other.getReturnType()) &&
|
||||
CharSequenceUtils.listEquals(getParameterTypes(), other.getParameterTypes());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
|
||||
BuilderTypeReference, BuilderProtoReference, BuilderFieldReference, BuilderMethodReference,
|
||||
BuilderTypeReference, BuilderMethodProtoReference, BuilderFieldReference, BuilderMethodReference,
|
||||
BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
|
||||
BuilderEncodedValue, BuilderAnnotationElement> {
|
||||
|
||||
@ -176,6 +176,10 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
||||
return context.methodPool.internMethod(method);
|
||||
}
|
||||
|
||||
@Nonnull public BuilderMethodProtoReference internMethodProtoReference(@Nonnull MethodProtoReference methodProto) {
|
||||
return context.protoPool.internMethodProto(methodProto);
|
||||
}
|
||||
|
||||
@Nonnull public BuilderReference internReference(@Nonnull Reference reference) {
|
||||
if (reference instanceof StringReference) {
|
||||
return internStringReference(((StringReference)reference).getString());
|
||||
@ -189,6 +193,9 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
|
||||
if (reference instanceof FieldReference) {
|
||||
return internFieldReference((FieldReference)reference);
|
||||
}
|
||||
if (reference instanceof MethodProtoReference) {
|
||||
return internMethodProtoReference((MethodProtoReference) reference);
|
||||
}
|
||||
throw new IllegalArgumentException("Could not determine type of reference");
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,6 @@ import org.jf.dexlib2.iface.value.*;
|
||||
import org.jf.dexlib2.writer.DexWriter;
|
||||
import org.jf.dexlib2.writer.io.DexDataStore;
|
||||
import org.jf.dexlib2.writer.io.FileDataStore;
|
||||
import org.jf.dexlib2.writer.pool.ProtoPool.Key;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -51,8 +50,8 @@ import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
public class DexPool extends DexWriter<CharSequence, StringReference, CharSequence, TypeReference, Key,
|
||||
FieldReference, MethodReference, PoolClassDef,
|
||||
public class DexPool extends DexWriter<CharSequence, StringReference, CharSequence, TypeReference,
|
||||
MethodProtoReference, FieldReference, MethodReference, PoolClassDef,
|
||||
Annotation, Set<? extends Annotation>,
|
||||
TypeListPool.Key<? extends Collection<? extends CharSequence>>, Field, PoolMethod,
|
||||
EncodedValue, AnnotationElement> {
|
||||
|
@ -31,13 +31,14 @@
|
||||
|
||||
package org.jf.dexlib2.writer.pool;
|
||||
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
import org.jf.dexlib2.writer.MethodSection;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class MethodPool extends BaseIndexPool<MethodReference>
|
||||
implements MethodSection<CharSequence, CharSequence, ProtoPool.Key, MethodReference, PoolMethod> {
|
||||
implements MethodSection<CharSequence, CharSequence, MethodProtoReference, MethodReference, PoolMethod> {
|
||||
@Nonnull private final StringPool stringPool;
|
||||
@Nonnull private final TypePool typePool;
|
||||
@Nonnull private final ProtoPool protoPool;
|
||||
@ -53,7 +54,7 @@ public class MethodPool extends BaseIndexPool<MethodReference>
|
||||
Integer prev = internedItems.put(method, 0);
|
||||
if (prev == null) {
|
||||
typePool.intern(method.getDefiningClass());
|
||||
protoPool.intern(method);
|
||||
protoPool.intern(new PoolMethodProto(method));
|
||||
stringPool.intern(method.getName());
|
||||
}
|
||||
}
|
||||
@ -62,12 +63,12 @@ public class MethodPool extends BaseIndexPool<MethodReference>
|
||||
return methodReference.getDefiningClass();
|
||||
}
|
||||
|
||||
@Nonnull @Override public ProtoPool.Key getPrototype(@Nonnull MethodReference methodReference) {
|
||||
return new ProtoPool.Key(methodReference);
|
||||
@Nonnull @Override public MethodProtoReference getPrototype(@Nonnull MethodReference methodReference) {
|
||||
return new PoolMethodProto(methodReference);
|
||||
}
|
||||
|
||||
@Nonnull @Override public ProtoPool.Key getPrototype(@Nonnull PoolMethod poolMethod) {
|
||||
return new ProtoPool.Key(poolMethod);
|
||||
@Nonnull @Override public MethodProtoReference getPrototype(@Nonnull PoolMethod poolMethod) {
|
||||
return new PoolMethodProto(poolMethod);
|
||||
}
|
||||
|
||||
@Nonnull @Override public CharSequence getName(@Nonnull MethodReference methodReference) {
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2016, 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.writer.pool;
|
||||
|
||||
import org.jf.dexlib2.base.reference.BaseMethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PoolMethodProto extends BaseMethodProtoReference implements MethodProtoReference {
|
||||
private final MethodReference methodReference;
|
||||
|
||||
public PoolMethodProto(MethodReference methodReference) {
|
||||
this.methodReference = methodReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends CharSequence> getParameterTypes() {
|
||||
return methodReference.getParameterTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return methodReference.getReturnType();
|
||||
}
|
||||
}
|
@ -31,21 +31,18 @@
|
||||
|
||||
package org.jf.dexlib2.writer.pool;
|
||||
|
||||
import com.google.common.collect.Ordering;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
import org.jf.dexlib2.iface.reference.MethodProtoReference;
|
||||
import org.jf.dexlib2.util.MethodUtil;
|
||||
import org.jf.dexlib2.writer.pool.ProtoPool.Key;
|
||||
import org.jf.dexlib2.writer.ProtoSection;
|
||||
import org.jf.util.CharSequenceUtils;
|
||||
import org.jf.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ProtoPool extends BaseIndexPool<Key>
|
||||
implements ProtoSection<CharSequence, CharSequence, Key, TypeListPool.Key<? extends Collection<? extends CharSequence>>> {
|
||||
public class ProtoPool extends BaseIndexPool<MethodProtoReference>
|
||||
implements ProtoSection<CharSequence, CharSequence, MethodProtoReference,
|
||||
TypeListPool.Key<? extends Collection<? extends CharSequence>>> {
|
||||
@Nonnull private final StringPool stringPool;
|
||||
@Nonnull private final TypePool typePool;
|
||||
@Nonnull private final TypeListPool typeListPool;
|
||||
@ -57,78 +54,25 @@ public class ProtoPool extends BaseIndexPool<Key>
|
||||
this.typeListPool = typeListPool;
|
||||
}
|
||||
|
||||
public void intern(@Nonnull MethodReference method) {
|
||||
// We can't use method directly, because it is likely a full MethodReference. We use a wrapper that computes
|
||||
// hashCode and equals based only on the prototype fields
|
||||
Key key = new Key(method);
|
||||
Integer prev = internedItems.put(key, 0);
|
||||
public void intern(@Nonnull MethodProtoReference reference) {
|
||||
Integer prev = internedItems.put(reference, 0);
|
||||
if (prev == null) {
|
||||
stringPool.intern(key.getShorty());
|
||||
typePool.intern(method.getReturnType());
|
||||
typeListPool.intern(method.getParameterTypes());
|
||||
stringPool.intern(getShorty(reference));
|
||||
typePool.intern(reference.getReturnType());
|
||||
typeListPool.intern(reference.getParameterTypes());
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull @Override public CharSequence getShorty(@Nonnull Key key) {
|
||||
return key.getShorty();
|
||||
@Nonnull @Override public CharSequence getShorty(@Nonnull MethodProtoReference reference) {
|
||||
return MethodUtil.getShorty(reference.getParameterTypes(), reference.getReturnType());
|
||||
}
|
||||
|
||||
@Nonnull @Override public CharSequence getReturnType(@Nonnull Key key) {
|
||||
return key.getReturnType();
|
||||
@Nonnull @Override public CharSequence getReturnType(@Nonnull MethodProtoReference protoReference) {
|
||||
return protoReference.getReturnType();
|
||||
}
|
||||
|
||||
@Nullable @Override public TypeListPool.Key<List<? extends CharSequence>> getParameters(@Nonnull Key key) {
|
||||
return new TypeListPool.Key<List<? extends CharSequence>>(key.getParameters());
|
||||
}
|
||||
|
||||
public static class Key implements Comparable<Key> {
|
||||
@Nonnull private final MethodReference method;
|
||||
|
||||
public Key(@Nonnull MethodReference method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Nonnull public String getReturnType() { return method.getReturnType(); }
|
||||
@Nonnull public List<? extends CharSequence> getParameters() {
|
||||
return method.getParameterTypes();
|
||||
}
|
||||
|
||||
public String getShorty() {
|
||||
return MethodUtil.getShorty(method.getParameterTypes(), method.getReturnType());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
for (CharSequence paramType: getParameters()) {
|
||||
sb.append(paramType);
|
||||
}
|
||||
sb.append(')');
|
||||
sb.append(getReturnType());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getReturnType().hashCode();
|
||||
return hashCode*31 + CharSequenceUtils.listHashCode(getParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o instanceof Key) {
|
||||
Key other = (Key)o;
|
||||
return getReturnType().equals(other.getReturnType()) &&
|
||||
CharSequenceUtils.listEquals(getParameters(), other.getParameters());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nonnull Key o) {
|
||||
int res = getReturnType().compareTo(o.getReturnType());
|
||||
if (res != 0) return res;
|
||||
return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameters(), o.getParameters());
|
||||
}
|
||||
@Nullable @Override public TypeListPool.Key<List<? extends CharSequence>> getParameters(
|
||||
@Nonnull MethodProtoReference methodProto) {
|
||||
return new TypeListPool.Key<List<? extends CharSequence>>(methodProto.getParameterTypes());
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,8 @@ tokens {
|
||||
INSTRUCTION_FORMAT3rc_TYPE;
|
||||
INSTRUCTION_FORMAT3rmi_METHOD;
|
||||
INSTRUCTION_FORMAT3rms_METHOD;
|
||||
INSTRUCTION_FORMAT45cc_METHOD;
|
||||
INSTRUCTION_FORMAT4rcc_METHOD;
|
||||
INSTRUCTION_FORMAT51l;
|
||||
LINE_COMMENT;
|
||||
LINE_DIRECTIVE;
|
||||
@ -234,6 +236,8 @@ tokens {
|
||||
I_STATEMENT_FORMAT35c_TYPE;
|
||||
I_STATEMENT_FORMAT3rc_METHOD;
|
||||
I_STATEMENT_FORMAT3rc_TYPE;
|
||||
I_STATEMENT_FORMAT45cc_METHOD;
|
||||
I_STATEMENT_FORMAT4rcc_METHOD;
|
||||
I_STATEMENT_FORMAT51l;
|
||||
I_STATEMENT_ARRAY_DATA;
|
||||
I_STATEMENT_PACKED_SWITCH;
|
||||
@ -581,6 +585,8 @@ simple_name
|
||||
| INSTRUCTION_FORMAT35c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_TYPE]
|
||||
| INSTRUCTION_FORMAT35mi_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35mi_METHOD]
|
||||
| INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD]
|
||||
| INSTRUCTION_FORMAT45cc_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT45cc_METHOD]
|
||||
| INSTRUCTION_FORMAT4rcc_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT4rcc_METHOD]
|
||||
| INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l];
|
||||
|
||||
member_name
|
||||
@ -849,6 +855,8 @@ instruction
|
||||
| insn_format3rc_type
|
||||
| insn_format3rmi_method
|
||||
| insn_format3rms_method
|
||||
| insn_format45cc_method
|
||||
| insn_format4rcc_method
|
||||
| insn_format51l
|
||||
| insn_array_data_directive
|
||||
| insn_packed_switch_directive
|
||||
@ -1106,6 +1114,16 @@ insn_format3rms_method
|
||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
|
||||
};
|
||||
|
||||
insn_format45cc_method
|
||||
: //e.g. invoke-polymorphic {v0..v1}, java/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (I)J
|
||||
INSTRUCTION_FORMAT45cc_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA method_reference COMMA method_prototype
|
||||
-> ^(I_STATEMENT_FORMAT45cc_METHOD[$start, "I_STATEMENT_FORMAT45cc_METHOD"] INSTRUCTION_FORMAT45cc_METHOD register_list method_reference method_prototype);
|
||||
|
||||
insn_format4rcc_method
|
||||
: //e.g. invoke-polymorphic/range {v0,v1}, java/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (I)J
|
||||
INSTRUCTION_FORMAT4rcc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA method_reference COMMA method_prototype
|
||||
-> ^(I_STATEMENT_FORMAT4rcc_METHOD[$start, "I_STATEMENT_FORMAT4rcc_METHOD"] INSTRUCTION_FORMAT4rcc_METHOD register_range method_reference method_prototype);
|
||||
|
||||
insn_format51l
|
||||
: //e.g. const-wide v0, 5000000000L
|
||||
INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal
|
||||
|
@ -62,6 +62,7 @@ import org.jf.dexlib2.immutable.ImmutableAnnotation;
|
||||
import org.jf.dexlib2.immutable.ImmutableAnnotationElement;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodProtoReference;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableReference;
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
|
||||
import org.jf.dexlib2.immutable.value.*;
|
||||
@ -766,6 +767,8 @@ instruction
|
||||
| insn_format35c_type
|
||||
| insn_format3rc_method
|
||||
| insn_format3rc_type
|
||||
| insn_format45cc_method
|
||||
| insn_format4rcc_method
|
||||
| insn_format51l_type
|
||||
| insn_array_data_directive
|
||||
| insn_packed_switch_directive
|
||||
@ -1181,6 +1184,47 @@ insn_format3rc_type
|
||||
dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
|
||||
};
|
||||
|
||||
insn_format45cc_method
|
||||
: //e.g. invoke-polymorphic {v0, v1}, java/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (I)J
|
||||
^(I_STATEMENT_FORMAT45cc_METHOD INSTRUCTION_FORMAT45cc_METHOD register_list method_reference method_prototype)
|
||||
{
|
||||
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT45cc_METHOD.text);
|
||||
|
||||
//this depends on the fact that register_list returns a byte[5]
|
||||
byte[] registers = $register_list.registers;
|
||||
byte registerCount = $register_list.registerCount;
|
||||
|
||||
ImmutableMethodReference methodReference = $method_reference.methodReference;
|
||||
ImmutableMethodProtoReference methodProtoReference = new ImmutableMethodProtoReference(
|
||||
$method_prototype.parameters,
|
||||
$method_prototype.returnType);
|
||||
|
||||
$method::methodBuilder.addInstruction(new BuilderInstruction45cc(opcode, registerCount, registers[0], registers[1],
|
||||
registers[2], registers[3], registers[4],
|
||||
dexBuilder.internMethodReference(methodReference),
|
||||
dexBuilder.internMethodProtoReference(methodProtoReference)));
|
||||
};
|
||||
|
||||
insn_format4rcc_method
|
||||
: //e.g. invoke-polymorphic {v0..v1}, java/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (I)J
|
||||
^(I_STATEMENT_FORMAT4rcc_METHOD INSTRUCTION_FORMAT4rcc_METHOD register_range method_reference method_prototype)
|
||||
{
|
||||
Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT4rcc_METHOD.text);
|
||||
int startRegister = $register_range.startRegister;
|
||||
int endRegister = $register_range.endRegister;
|
||||
|
||||
int registerCount = endRegister-startRegister+1;
|
||||
|
||||
ImmutableMethodReference methodReference = $method_reference.methodReference;
|
||||
ImmutableMethodProtoReference methodProtoReference = new ImmutableMethodProtoReference(
|
||||
$method_prototype.parameters,
|
||||
$method_prototype.returnType);
|
||||
|
||||
$method::methodBuilder.addInstruction(new BuilderInstruction4rcc(opcode, startRegister, registerCount,
|
||||
dexBuilder.internMethodReference(methodReference),
|
||||
dexBuilder.internMethodProtoReference(methodProtoReference)));
|
||||
};
|
||||
|
||||
insn_format51l_type
|
||||
: //e.g. const-wide v0, 5000000000L
|
||||
^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal)
|
||||
|
@ -624,6 +624,14 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} |
|
||||
return newToken(INSTRUCTION_FORMAT3rms_METHOD);
|
||||
}
|
||||
|
||||
"invoke-polymorphic" {
|
||||
return newToken(INSTRUCTION_FORMAT45cc_METHOD);
|
||||
}
|
||||
|
||||
"invoke-polymorphic/range" {
|
||||
return newToken(INSTRUCTION_FORMAT4rcc_METHOD);
|
||||
}
|
||||
|
||||
"const-wide" {
|
||||
return newToken(INSTRUCTION_FORMAT51l);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user