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:
Narayan Kamath 2016-08-04 17:31:18 +01:00
parent a5d82813f1
commit afc1f15939
39 changed files with 1125 additions and 241 deletions

View File

@ -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;
String classContext = null;
if (methodDef.classDef.options.useImplicitReferences) {
classContext = methodDef.method.getDefiningClass();
}
try {
Reference reference = referenceInstruction.getReference();
String classContext = null;
if (methodDef.classDef.options.useImplicitReferences) {
classContext = methodDef.method.getDefiningClass();
}
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;

View File

@ -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),

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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,14 +42,15 @@ 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,
@Nonnull BuilderTypeReference returnType) {
public BuilderMethodProtoReference(@Nonnull BuilderStringReference shorty, @Nonnull BuilderTypeList parameterTypes,
@Nonnull BuilderTypeReference returnType) {
this.shorty = shorty;
this.parameterTypes = parameterTypes;
this.returnType = returnType;
@ -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;
}
}

View File

@ -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;

View File

@ -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) {
return key.index;
@Override public int getItemIndex(@Nonnull BuilderMethodProtoReference proto) {
return proto.getIndex();
}
@Nonnull @Override public Collection<? extends Entry<? extends BuilderProtoReference, Integer>> getItems() {
return new BuilderMapEntryCollection<BuilderProtoReference>(internedItems.values()) {
@Override protected int getValue(@Nonnull BuilderProtoReference key) {
@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;
}
@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;
}
}
}

View File

@ -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");
}

View File

@ -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> {

View File

@ -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) {

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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

View File

@ -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)

View File

@ -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);
}