From afc1f1593936326e1c99f8328bbce8b495865000 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Thu, 4 Aug 2016 17:31:18 +0100 Subject: [PATCH] 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 --- .../Format/InstructionMethodItem.java | 66 +++++++++--- .../src/main/java/org/jf/dexlib2/Format.java | 2 + .../src/main/java/org/jf/dexlib2/Opcode.java | 15 ++- .../java/org/jf/dexlib2/ReferenceType.java | 9 +- .../reference/BaseMethodProtoReference.java | 66 ++++++++++++ .../instruction/BuilderInstruction35c.java | 2 +- .../instruction/BuilderInstruction45cc.java | 87 +++++++++++++++ .../instruction/BuilderInstruction4rcc.java | 72 +++++++++++++ .../instruction/DexBackedInstruction.java | 4 + .../instruction/DexBackedInstruction45cc.java | 101 ++++++++++++++++++ .../instruction/DexBackedInstruction4rcc.java | 80 ++++++++++++++ .../DexBackedMethodProtoReference.java | 77 +++++++++++++ .../reference/DexBackedReference.java | 2 + .../instruction/DualReferenceInstruction.java | 22 ++-- .../instruction/formats/Instruction45cc.java | 38 +++++++ .../instruction/formats/Instruction4rcc.java | 38 +++++++ .../iface/reference/MethodProtoReference.java | 96 +++++++++++++++++ .../instruction/ImmutableInstruction35c.java | 2 +- .../instruction/ImmutableInstruction35mi.java | 2 +- .../instruction/ImmutableInstruction35ms.java | 2 +- .../ImmutableMethodProtoReference.java | 72 +++++++++++++ .../reference/ImmutableReferenceFactory.java | 5 + .../org/jf/dexlib2/util/Preconditions.java | 2 +- .../org/jf/dexlib2/util/ReferenceUtil.java | 19 +++- .../java/org/jf/dexlib2/writer/DexWriter.java | 27 +++-- .../jf/dexlib2/writer/InstructionWriter.java | 74 ++++++++++--- .../org/jf/dexlib2/writer/MethodSection.java | 8 +- .../writer/builder/BuilderMethodPool.java | 8 +- ....java => BuilderMethodProtoReference.java} | 30 ++---- .../builder/BuilderMethodReference.java | 4 +- .../writer/builder/BuilderProtoPool.java | 91 +++++----------- .../jf/dexlib2/writer/builder/DexBuilder.java | 9 +- .../org/jf/dexlib2/writer/pool/DexPool.java | 5 +- .../jf/dexlib2/writer/pool/MethodPool.java | 13 +-- .../dexlib2/writer/pool/PoolMethodProto.java | 56 ++++++++++ .../org/jf/dexlib2/writer/pool/ProtoPool.java | 88 +++------------ smali/src/main/antlr/smaliParser.g | 20 +++- smali/src/main/antlr/smaliTreeWalker.g | 44 ++++++++ smali/src/main/jflex/smaliLexer.jflex | 8 ++ 39 files changed, 1125 insertions(+), 241 deletions(-) create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodProtoReference.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction45cc.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction4rcc.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction4rcc.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java rename baksmali/src/test/java/org/jf/baksmali/LambdaTest.java => dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/DualReferenceInstruction.java (73%) create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodProtoReference.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableMethodProtoReference.java rename dexlib2/src/main/java/org/jf/dexlib2/writer/builder/{BuilderProtoReference.java => BuilderMethodProtoReference.java} (69%) create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethodProto.java diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index fc43d6f1..39485c90 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -79,11 +79,20 @@ public class InstructionMethodItem 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 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 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 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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Format.java b/dexlib2/src/main/java/org/jf/dexlib2/Format.java index ee34aa50..42e8e144 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Format.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Format.java @@ -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), diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java index 3a642358..9559760a 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java @@ -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 versionConstraints, String opcodeName, int referenceType, Format format, int flags) { + this(versionConstraints, opcodeName, referenceType, -1, format, flags); + } + + Opcode(List versionConstraints, String opcodeName, int referenceType, int referenceType2, + Format format, int flags) { ImmutableRangeMap.Builder apiToValueBuilder = ImmutableRangeMap.builder(); ImmutableRangeMap.Builder 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; } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java b/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java index 3371f818..fa8b9687 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/ReferenceType.java @@ -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); } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodProtoReference.java b/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodProtoReference.java new file mode 100644 index 00000000..c0d38b0b --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/base/reference/BaseMethodProtoReference.java @@ -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()); + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35c.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35c.java index 283464fe..5ec58a92 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35c.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction35c.java @@ -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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction45cc.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction45cc.java new file mode 100644 index 00000000..b0e3f427 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction45cc.java @@ -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; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction4rcc.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction4rcc.java new file mode 100644 index 00000000..3ee7ef9d --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction4rcc.java @@ -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; } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java index ac82f4b4..2973398a 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction.java @@ -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: diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.java new file mode 100644 index 00000000..bbdc229f --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.java @@ -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; + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction4rcc.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction4rcc.java new file mode 100644 index 00000000..629e753b --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction4rcc.java @@ -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; + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java new file mode 100644 index 00000000..12875b7b --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java @@ -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 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() { + @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)); + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedReference.java index b63c37c2..99d66ecd 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedReference.java @@ -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); } diff --git a/baksmali/src/test/java/org/jf/baksmali/LambdaTest.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/DualReferenceInstruction.java similarity index 73% rename from baksmali/src/test/java/org/jf/baksmali/LambdaTest.java rename to dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/DualReferenceInstruction.java index 5431df54..0f1f81b2 100644 --- a/baksmali/src/test/java/org/jf/baksmali/LambdaTest.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/DualReferenceInstruction.java @@ -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(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.java new file mode 100644 index 00000000..221fd623 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.java @@ -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 { +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.java new file mode 100644 index 00000000..d0b930b1 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.java @@ -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 { +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodProtoReference.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodProtoReference.java new file mode 100644 index 00000000..e150c214 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodProtoReference.java @@ -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 { + /** + * 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 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: + * + *
+     * {@code
+     * int hashCode =  getReturnType().hashCode();
+     * hashCode = hashCode*31 + CharSequenceUtils.listHashCode(getParameters());
+     * }
+ * + * @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); +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java index 20976f80..7ac1a8f6 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35c.java @@ -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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java index def7eb60..5e58cae9 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35mi.java @@ -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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java index 16d7e913..0130f474 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction35ms.java @@ -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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableMethodProtoReference.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableMethodProtoReference.java new file mode 100644 index 00000000..8c2afe59 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableMethodProtoReference.java @@ -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 parameters; + @Nonnull protected final String returnType; + + public ImmutableMethodProtoReference(@Nullable Iterable 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 getParameterTypes() { + return parameters; + } + + @Override + public String getReturnType() { + return returnType; + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableReferenceFactory.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableReferenceFactory.java index 0d27e47f..d0007479 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableReferenceFactory.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/reference/ImmutableReferenceFactory.java @@ -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); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java b/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java index 51c083ca..3b30d075 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java @@ -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)); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/ReferenceUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/util/ReferenceUtil.java index 81b042ec..4e46a0e9 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/util/ReferenceUtil.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/ReferenceUtil.java @@ -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; } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java index 4e81f7fa..5329351e 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java @@ -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, + TypeRef extends TypeReference, ProtoRefKey extends MethodProtoReference, FieldRefKey extends FieldReference, MethodRefKey extends MethodReference, ClassKey extends Comparable, AnnotationKey extends Annotation, AnnotationSetKey, @@ -125,9 +126,9 @@ public abstract class DexWriter< protected final StringSection stringSection; protected final TypeSection typeSection; - protected final ProtoSection protoSection; + protected final ProtoSection protoSection; protected final FieldSection fieldSection; - protected final MethodSection methodSection; + protected final MethodSection methodSection; protected final ClassSection classSection; @@ -138,9 +139,9 @@ public abstract class DexWriter< protected DexWriter(Opcodes opcodes, StringSection stringSection, TypeSection typeSection, - ProtoSection protoSection, + ProtoSection protoSection, FieldSection fieldSection, - MethodSection methodSection, + MethodSection methodSection, ClassSection classSection, TypeListSection typeListSection, @@ -347,12 +348,12 @@ public abstract class DexWriter< protoSectionOffset = writer.getPosition(); int index = 0; - List> protoEntries = Lists.newArrayList(protoSection.getItems()); - Collections.sort(protoEntries, DexWriter.comparableKeyComparator()); + List> protoEntries = Lists.newArrayList(protoSection.getItems()); + Collections.sort(protoEntries, DexWriter.comparableKeyComparator()); - for (Map.Entry entry: protoEntries) { + for (Map.Entry 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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java index f16256c5..c240c515 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java @@ -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 { + FieldRefKey extends FieldReference, MethodRefKey extends MethodReference, + ProtoRefKey extends MethodProtoReference> { @Nonnull private final Opcodes opcodes; @Nonnull private final DexDataWriter writer; @Nonnull private final StringSection stringSection; @Nonnull private final TypeSection typeSection; @Nonnull private final FieldSection fieldSection; @Nonnull private final MethodSection methodSection; + @Nonnull private final ProtoSection protoSection; - @Nonnull static - InstructionWriter + @Nonnull static + InstructionWriter makeInstructionWriter( @Nonnull Opcodes opcodes, @Nonnull DexDataWriter writer, @Nonnull StringSection stringSection, @Nonnull TypeSection typeSection, @Nonnull FieldSection fieldSection, - @Nonnull MethodSection methodSection) { - return new InstructionWriter( - opcodes, writer, stringSection, typeSection, fieldSection, methodSection); + @Nonnull MethodSection methodSection, + @Nonnull ProtoSection protoSection) { + return new InstructionWriter( + opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection); } InstructionWriter(@Nonnull Opcodes opcodes, @@ -77,13 +84,15 @@ public class InstructionWriter stringSection, @Nonnull TypeSection typeSection, @Nonnull FieldSection fieldSection, - @Nonnull MethodSection methodSection) { + @Nonnull MethodSection methodSection, + @Nonnull ProtoSection 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 +public interface MethodSection extends IndexSection { @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); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodPool.java index 7dc924e7..2c5dd816 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodPool.java @@ -43,7 +43,7 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; class BuilderMethodPool implements MethodSection{ + BuilderMethodProtoReference, BuilderMethodReference, BuilderMethod>{ @Nonnull private final BuilderContext context; @Nonnull private final ConcurrentMap internedItems = Maps.newConcurrentMap(); @@ -61,7 +61,7 @@ class BuilderMethodPool implements MethodSection { +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; } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodReference.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodReference.java index c913efa5..96708444 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethodReference.java @@ -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; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderProtoPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderProtoPool.java index 6ed18fe8..de19fa30 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderProtoPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderProtoPool.java @@ -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 { + implements ProtoSection { @Nonnull private final BuilderContext context; - @Nonnull private final ConcurrentMap internedItems = + @Nonnull private final ConcurrentMap internedItems = Maps.newConcurrentMap(); BuilderProtoPool(@Nonnull BuilderContext context) { this.context = context; } - @Nonnull public BuilderProtoReference internProto(@Nonnull List 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> getItems() { - return new BuilderMapEntryCollection(internedItems.values()) { - @Override protected int getValue(@Nonnull BuilderProtoReference key) { + @Nonnull @Override public Collection> getItems() { + return new BuilderMapEntryCollection(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 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 parameters; - @Nonnull private final String returnType; - - public Key(@Nonnull List parameters, @Nonnull String returnType) { - this.parameters = parameters; - this.returnType = returnType; - } - - @Nonnull public List 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; - } - } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java index d1190249..b7507fa6 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java @@ -54,7 +54,7 @@ import java.util.List; import java.util.Set; public class DexBuilder extends DexWriter { @@ -176,6 +176,10 @@ public class DexBuilder extends DexWriter, TypeListPool.Key>, Field, PoolMethod, EncodedValue, AnnotationElement> { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/MethodPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/MethodPool.java index 7ae42fb6..8103d319 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/MethodPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/MethodPool.java @@ -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 - implements MethodSection { + implements MethodSection { @Nonnull private final StringPool stringPool; @Nonnull private final TypePool typePool; @Nonnull private final ProtoPool protoPool; @@ -53,7 +54,7 @@ public class MethodPool extends BaseIndexPool 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 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) { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethodProto.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethodProto.java new file mode 100644 index 00000000..d180be1d --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethodProto.java @@ -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 getParameterTypes() { + return methodReference.getParameterTypes(); + } + + @Override + public String getReturnType() { + return methodReference.getReturnType(); + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ProtoPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ProtoPool.java index eeabdf4a..523e5f4d 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ProtoPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ProtoPool.java @@ -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 - implements ProtoSection>> { +public class ProtoPool extends BaseIndexPool + implements ProtoSection>> { @Nonnull private final StringPool stringPool; @Nonnull private final TypePool typePool; @Nonnull private final TypeListPool typeListPool; @@ -57,78 +54,25 @@ public class ProtoPool extends BaseIndexPool 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> getParameters(@Nonnull Key key) { - return new TypeListPool.Key>(key.getParameters()); - } - - public static class Key implements Comparable { - @Nonnull private final MethodReference method; - - public Key(@Nonnull MethodReference method) { - this.method = method; - } - - @Nonnull public String getReturnType() { return method.getReturnType(); } - @Nonnull public List 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> getParameters( + @Nonnull MethodProtoReference methodProto) { + return new TypeListPool.Key>(methodProto.getParameterTypes()); } } diff --git a/smali/src/main/antlr/smaliParser.g b/smali/src/main/antlr/smaliParser.g index fcccbe80..29148f7b 100644 --- a/smali/src/main/antlr/smaliParser.g +++ b/smali/src/main/antlr/smaliParser.g @@ -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 @@ -1141,4 +1159,4 @@ insn_sparse_switch_directive (fixed_32bit_literal ARROW label_ref)* END_SPARSE_SWITCH_DIRECTIVE -> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"] - ^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal label_ref)*)); \ No newline at end of file + ^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal label_ref)*)); diff --git a/smali/src/main/antlr/smaliTreeWalker.g b/smali/src/main/antlr/smaliTreeWalker.g index c3a50994..7f5657a5 100644 --- a/smali/src/main/antlr/smaliTreeWalker.g +++ b/smali/src/main/antlr/smaliTreeWalker.g @@ -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) diff --git a/smali/src/main/jflex/smaliLexer.jflex b/smali/src/main/jflex/smaliLexer.jflex index 2f57a438..e0010a93 100644 --- a/smali/src/main/jflex/smaliLexer.jflex +++ b/smali/src/main/jflex/smaliLexer.jflex @@ -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); }