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 6f788433..d58b2b68 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.implicitReferences) { + classContext = methodDef.method.getDefiningClass(); + } + try { Reference reference = referenceInstruction.getReference(); - - String classContext = null; - if (methodDef.classDef.options.implicitReferences) { - 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) { @@ -308,11 +330,6 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeThirdRegister(writer); break; - case Format25x: - writeOpcode(writer); - writer.write(' '); - writeInvoke25xRegisters(writer); // vC, {vD, ...} - break; case Format35c: writeOpcode(writer); writer.write(' '); @@ -355,6 +372,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; @@ -438,43 +473,6 @@ public class InstructionMethodItem extends MethodItem { writer.write('}'); } - protected void writeInvoke25xRegisters(IndentingWriter writer) throws IOException { - OneFixedFourParameterRegisterInstruction instruction = - (OneFixedFourParameterRegisterInstruction)this.instruction; - final int parameterRegCount = instruction.getParameterRegisterCount(); - - writeRegister(writer, instruction.getRegisterFixedC()); // fixed register always present - - writer.write(", {"); - switch (parameterRegCount) { - case 1: - writeRegister(writer, instruction.getRegisterParameterD()); - break; - case 2: - writeRegister(writer, instruction.getRegisterParameterD()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterParameterE()); - break; - case 3: - writeRegister(writer, instruction.getRegisterParameterD()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterParameterE()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterParameterF()); - break; - case 4: - writeRegister(writer, instruction.getRegisterParameterD()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterParameterE()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterParameterF()); - writer.write(", "); - writeRegister(writer, instruction.getRegisterParameterG()); - break; - } - writer.write('}'); - } - protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException { RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction; diff --git a/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java b/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java new file mode 100644 index 00000000..28def63d --- /dev/null +++ b/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java @@ -0,0 +1,54 @@ +/* + * 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.baksmali; + +import org.junit.Test; + +/** + * Test for a bug related to debug items that refer to a register that's outside the expected range for a method + */ +public class LargeLocalTest extends IdenticalRoundtripTest { + @Test + public void testLargeEndLocal() { + runTest("LargeEndLocal"); + } + + @Test + public void testLargeRestartLocal() { + runTest("LargeRestartLocal"); + } + + @Test + public void testLargeStartLocal() { + runTest("LargeStartLocal"); + } +} diff --git a/baksmali/src/test/resources/LambdaTest/HelloWorldLambda.smali b/baksmali/src/test/resources/LambdaTest/HelloWorldLambda.smali deleted file mode 100644 index d70ced50..00000000 --- a/baksmali/src/test/resources/LambdaTest/HelloWorldLambda.smali +++ /dev/null @@ -1,55 +0,0 @@ -.class public LHelloWorldLambda; - -#Ye olde hello world application (with lambdas!) -#To assemble and run this on a phone or emulator: -# -#java -jar smali.jar -o classes.dex HelloWorldLambda.smali HelloWorldFunctionalInterface.smali -#zip HelloWorld.zip classes.dex -#adb push HelloWorld.zip /data/local -#adb shell dalvikvm -cp /data/local/HelloWorld.zip HelloWorld -# -#if you get out of memory type errors when running smali.jar, try -#java -Xmx512m -jar smali.jar HelloWorldLambda.smali -#instead - -.super Ljava/lang/Object; - -.method public static doHelloWorld(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - .registers 6 # 4 parameters, 2 locals - liberate-variable v0, p0, "helloworld" - - sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; - invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V - - return-void -.end method - -.method public static main([Ljava/lang/String;)V - .registers 9 # 1 parameter, 8 locals - - sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; - - const-string v1, "Hello World!" - const-string v2, "How" # vD - const-string v3, "are" # vE - const-string v4, "you" # vF - const-string v5, "doing?" # vG - - capture-variable v1, "helloworld" - - # TODO: do I need to pass the type of the lambda's functional interface here as a type id? - create-lambda v1, LHelloWorldLambda;->doHelloWorld(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - # Method descriptor is not required here, because only the single-abstract method is ever invoked. - invoke-lambda v1, {v2, v3, v4, v5} - - box-lambda v6, v1 - invoke-virtual {v6, v2, v3, v4, v5}, LHelloWorldFunctionalInterface;->applyFourStrings(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - - # FIXME: should be \HelloWorldFunctionalInterface; instead of L...; - - # TODO: do we really need the type descriptor here at all? - unbox-lambda v7, v6, LHelloWorldFunctionalInterface; - invoke-lambda v7, {v2, v3, v4, v5} - - return-void -.end method diff --git a/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali b/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali new file mode 100644 index 00000000..8c7e72ce --- /dev/null +++ b/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali @@ -0,0 +1,11 @@ +.class LLargeRestartLocal; +.super Ljava/lang/Object; + + +# virtual methods +.method public static main([Ljava/lang/String;)V + .registers 2 + + .end local p99 + return-void +.end method diff --git a/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali b/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali new file mode 100644 index 00000000..41c60d02 --- /dev/null +++ b/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali @@ -0,0 +1,11 @@ +.class LLargeEndLocal; +.super Ljava/lang/Object; + + +# virtual methods +.method public static main([Ljava/lang/String;)V + .registers 2 + + .restart local p99 + return-void +.end method diff --git a/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali b/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali new file mode 100644 index 00000000..b811844b --- /dev/null +++ b/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali @@ -0,0 +1,11 @@ +.class LLargeStartLocal; +.super Ljava/lang/Object; + + +# virtual methods +.method public static main([Ljava/lang/String;)V + .registers 2 + + .local p99, "blah":I + return-void +.end method diff --git a/build.gradle b/build.gradle index 358c7f72..8d1b2f34 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ apply plugin: 'idea' -version = '2.1.2' +version = '2.1.3' if (!('release' in gradle.startParameter.taskNames)) { def versionSuffix @@ -104,8 +104,7 @@ subprojects { antlr_runtime: 'org.antlr:antlr-runtime:3.5.2', antlr: 'org.antlr:antlr:3.5.2', stringtemplate: 'org.antlr:stringtemplate:3.2.1', - jflex: 'de.jflex:jflex:1.4.3', - jflex_plugin: 'co.tomlee.gradle.plugins:gradle-jflex-plugin:0.0.2', + jflex_plugin: 'org.xbib.gradle.plugin:gradle-plugin-jflex:1.1.0', proguard_gradle: 'net.sf.proguard:proguard-gradle:5.2.1', dx: 'com.google.android.tools:dx:1.7', gson: 'com.google.code.gson:gson:2.3.1', @@ -197,5 +196,5 @@ buildscript { } task wrapper(type: Wrapper) { - gradleVersion = '2.11' + gradleVersion = '2.14' } \ No newline at end of file diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Format.java b/dexlib2/src/main/java/org/jf/dexlib2/Format.java index ee34aa50..fd90a6dd 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/Format.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/Format.java @@ -51,7 +51,6 @@ public enum Format { Format22t(4), Format22x(4), Format23x(4), - Format25x(4), Format30t(6), Format31c(6), Format31i(6), @@ -63,6 +62,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..138c6c63 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), @@ -305,15 +305,8 @@ public enum Opcode SPARSE_SWITCH_PAYLOAD(0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0), ARRAY_PAYLOAD(0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0), - // Reuse the deprecated f3-ff opcodes in Art: - INVOKE_LAMBDA(allArtVersions(0xf3),"invoke-lambda", ReferenceType.NONE, Format.Format25x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.EXPERIMENTAL), - // TODO: What about JUMBO support if the string ID is too large? - CAPTURE_VARIABLE(allArtVersions(0xf5), "capture-variable", ReferenceType.STRING, Format.Format21c, Opcode.EXPERIMENTAL), - CREATE_LAMBDA(allArtVersions(0xf6), "create-lambda", ReferenceType.METHOD, Format.Format21c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL), - // 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); + 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 +352,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 +363,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 +384,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/analysis/ClassProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java index 1e0d0fa6..b1c10d2c 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java @@ -34,10 +34,7 @@ package org.jf.dexlib2.analysis; import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; +import com.google.common.collect.*; import com.google.common.primitives.Ints; import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.analysis.util.TypeProtoUtils; @@ -71,6 +68,8 @@ public class ClassProto implements TypeProto { protected boolean vtableFullyResolved = true; protected boolean interfacesFullyResolved = true; + protected Set unresolvedInterfaces = null; + public ClassProto(@Nonnull ClassPath classPath, @Nonnull String type) { if (type.charAt(0) != 'L') { throw new ExceptionWithContext("Cannot construct ClassProto for non reference type: %s", type); @@ -130,6 +129,7 @@ public class ClassProto implements TypeProto { private final Supplier> interfacesSupplier = Suppliers.memoize(new Supplier>() { @Override public LinkedHashMap get() { + Set unresolvedInterfaces = new HashSet(0); LinkedHashMap interfaces = Maps.newLinkedHashMap(); try { @@ -141,6 +141,7 @@ public class ClassProto implements TypeProto { interfaces.put(interfaceType, interfaceDef); } catch (UnresolvedClassException ex) { interfaces.put(interfaceType, null); + unresolvedInterfaces.add(interfaceType); interfacesFullyResolved = false; } @@ -151,11 +152,13 @@ public class ClassProto implements TypeProto { } } if (!interfaceProto.interfacesFullyResolved) { + unresolvedInterfaces.addAll(interfaceProto.getUnresolvedInterfaces()); interfacesFullyResolved = false; } } } } catch (UnresolvedClassException ex) { + unresolvedInterfaces.add(type); interfacesFullyResolved = false; } @@ -166,8 +169,8 @@ public class ClassProto implements TypeProto { interfaces.put(getType(), null); } + String superclass = getSuperclass(); try { - String superclass = getSuperclass(); if (superclass != null) { ClassProto superclassProto = (ClassProto) classPath.getClass(superclass); for (String superclassInterface: superclassProto.getInterfaces().keySet()) { @@ -176,17 +179,31 @@ public class ClassProto implements TypeProto { } } if (!superclassProto.interfacesFullyResolved) { + unresolvedInterfaces.addAll(superclassProto.getUnresolvedInterfaces()); interfacesFullyResolved = false; } } } catch (UnresolvedClassException ex) { + unresolvedInterfaces.add(superclass); interfacesFullyResolved = false; } + if (unresolvedInterfaces.size() > 0) { + ClassProto.this.unresolvedInterfaces = unresolvedInterfaces; + } + return interfaces; } }); + @Nonnull + protected Set getUnresolvedInterfaces() { + if (unresolvedInterfaces == null) { + return ImmutableSet.of(); + } + return unresolvedInterfaces; + } + /** * Gets the interfaces directly implemented by this class, or the interfaces they transitively implement. * @@ -201,7 +218,8 @@ public class ClassProto implements TypeProto { FluentIterable.from(getInterfaces().values()).filter(Predicates.notNull()); if (!interfacesFullyResolved) { - throw new UnresolvedClassException("Interfaces for class %s not fully resolved", getType()); + throw new UnresolvedClassException("Interfaces for class %s not fully resolved: %s", getType(), + String.join(",", getUnresolvedInterfaces())); } return directInterfaces; 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/MutableMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java index b1e5dbbf..148bafd1 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java @@ -615,9 +615,6 @@ public class MutableMethodImplementation implements MethodImplementation { case Format23x: setInstruction(location, newBuilderInstruction23x((Instruction23x) instruction)); return; - case Format25x: - setInstruction(location, newBuilderInstruction25x((Instruction25x) instruction)); - return; case Format30t: setInstruction(location, newBuilderInstruction30t(location.codeAddress, codeAddressToIndex, @@ -871,18 +868,6 @@ public class MutableMethodImplementation implements MethodImplementation { instruction.getReference()); } - @Nonnull - private BuilderInstruction25x newBuilderInstruction25x(@Nonnull Instruction25x instruction) { - return new BuilderInstruction25x( - instruction.getOpcode(), - instruction.getParameterRegisterCount(), - instruction.getRegisterFixedC(), - instruction.getRegisterParameterD(), - instruction.getRegisterParameterE(), - instruction.getRegisterParameterF(), - instruction.getRegisterParameterG()); - } - @Nonnull private BuilderInstruction3rc newBuilderInstruction3rc(@Nonnull Instruction3rc instruction) { return new BuilderInstruction3rc( diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction25x.java deleted file mode 100644 index 3783d2b6..00000000 --- a/dexlib2/src/main/java/org/jf/dexlib2/builder/instruction/BuilderInstruction25x.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015, 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.Instruction25x; -import org.jf.dexlib2.util.Preconditions; - -import javax.annotation.Nonnull; - -public class BuilderInstruction25x extends BuilderInstruction implements Instruction25x { - public static final Format FORMAT = Format.Format25x; - - protected final int parameterRegisterCount; - protected final int registerClosure; - protected final int registerD; - protected final int registerE; - protected final int registerF; - protected final int registerG; - - public BuilderInstruction25x(@Nonnull Opcode opcode, - int parameterRegisterCount, - int registerClosure, - int registerD, - int registerE, - int registerF, - int registerG) { - super(opcode); - this.parameterRegisterCount = - Preconditions.check25xParameterRegisterCount(parameterRegisterCount); - this.registerClosure = Preconditions.checkNibbleRegister(registerClosure); //at least 1 reg - this.registerD = (parameterRegisterCount>0) ? - Preconditions.checkNibbleRegister(registerD) : 0; - this.registerE = (parameterRegisterCount>1) ? - Preconditions.checkNibbleRegister(registerE) : 0; - this.registerF = (parameterRegisterCount>2) ? - Preconditions.checkNibbleRegister(registerF) : 0; - this.registerG = (parameterRegisterCount>3) ? - Preconditions.checkNibbleRegister(registerG) : 0; - } - - @Override public int getRegisterCount() { return parameterRegisterCount + 1; } - @Override public int getParameterRegisterCount() { return parameterRegisterCount; } - @Override public int getRegisterFixedC() { return registerClosure; } - @Override public int getRegisterParameterD() { return registerD; } - @Override public int getRegisterParameterE() { return registerE; } - @Override public int getRegisterParameterF() { return registerF; } - @Override public int getRegisterParameterG() { return registerG; } - - @Override public Format getFormat() { return FORMAT; } -} 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..975e6813 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 @@ -115,8 +115,6 @@ public abstract class DexBackedInstruction implements Instruction { return new DexBackedInstruction22x(dexFile, opcode, instructionStartOffset); case Format23x: return new DexBackedInstruction23x(dexFile, opcode, instructionStartOffset); - case Format25x: - return new DexBackedInstruction25x(dexFile, opcode, instructionStartOffset); case Format30t: return new DexBackedInstruction30t(dexFile, opcode, instructionStartOffset); case Format31c: @@ -139,6 +137,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/DexBackedInstruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.java similarity index 63% rename from dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction25x.java rename to dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.java index 80fb8767..bbdc229f 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction25x.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedInstruction45cc.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 @@ -33,51 +33,69 @@ package org.jf.dexlib2.dexbacked.instruction; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.dexbacked.DexBackedDexFile; -import org.jf.dexlib2.iface.instruction.formats.Instruction25x; +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 DexBackedInstruction25x extends DexBackedInstruction implements Instruction25x { - public DexBackedInstruction25x(@Nonnull DexBackedDexFile dexFile, - @Nonnull Opcode opcode, - int instructionStart) { +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 getParameterRegisterCount() + 1; - } - - @Override - public int getParameterRegisterCount() { + @Override public int getRegisterCount() { return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 1)); } @Override - public int getRegisterFixedC() { - return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 2)); + public int getRegisterC() { + return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 4)); } @Override - public int getRegisterParameterD() { - return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 2)); + public int getRegisterD() { + return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 4)); } @Override - public int getRegisterParameterE() { - return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 3)); + public int getRegisterE() { + return NibbleUtils.extractLowUnsignedNibble(dexFile.readUbyte(instructionStart + 5)); } @Override - public int getRegisterParameterF() { - return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 3)); + public int getRegisterF() { + return NibbleUtils.extractHighUnsignedNibble(dexFile.readUbyte(instructionStart + 5)); } @Override - public int getRegisterParameterG() { + 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/raw/CodeItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java index 27d72ad1..eeaff457 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java @@ -129,9 +129,6 @@ public class CodeItem { case Format10x: annotateInstruction10x(out, instruction); break; - case Format25x: - annotateInstruction25x(out, (Instruction25x) instruction); - break; case Format35c: annotateInstruction35c(out, (Instruction35c)instruction); break; @@ -285,30 +282,6 @@ public class CodeItem { instruction.getOpcode().name, Joiner.on(", ").join(args), reference)); } - private void annotateInstruction25x(@Nonnull AnnotatedBytes out, - @Nonnull Instruction25x instruction) { - List args = Lists.newArrayList(); - - int registerCount = instruction.getRegisterCount(); //at least 1. - if (registerCount == 2) { - args.add(formatRegister(instruction.getRegisterParameterD())); - } else if (registerCount == 3) { - args.add(formatRegister(instruction.getRegisterParameterD())); - args.add(formatRegister(instruction.getRegisterParameterE())); - } else if (registerCount == 4) { - args.add(formatRegister(instruction.getRegisterParameterD())); - args.add(formatRegister(instruction.getRegisterParameterE())); - args.add(formatRegister(instruction.getRegisterParameterF())); - } else if (registerCount == 5) { - args.add(formatRegister(instruction.getRegisterParameterD())); - args.add(formatRegister(instruction.getRegisterParameterE())); - args.add(formatRegister(instruction.getRegisterParameterF())); - args.add(formatRegister(instruction.getRegisterParameterG())); - } - out.annotate(6, String.format("%s %s, {%s}", - instruction.getOpcode().name, instruction.getRegisterFixedC(), Joiner.on(", ").join(args))); - } - private void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) { int startRegister = instruction.getStartRegister(); int endRegister = startRegister + instruction.getRegisterCount() - 1; 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/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java index 8a32b5f6..ef240718 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java @@ -182,7 +182,9 @@ public abstract class DebugInfo implements Iterable { String type = dexFile.getOptionalType(reader.readSmallUleb128() - 1); ImmutableStartLocal startLocal = new ImmutableStartLocal(codeAddress, register, name, type, null); - locals[register] = startLocal; + if (register >= 0 && register < locals.length) { + locals[register] = startLocal; + } return startLocal; } case DebugItemType.START_LOCAL_EXTENDED: { @@ -192,13 +194,23 @@ public abstract class DebugInfo implements Iterable { String signature = dexFile.getOptionalString(reader.readSmallUleb128() - 1); ImmutableStartLocal startLocal = new ImmutableStartLocal(codeAddress, register, name, type, signature); - locals[register] = startLocal; + if (register >= 0 && register < locals.length) { + locals[register] = startLocal; + } return startLocal; } case DebugItemType.END_LOCAL: { int register = reader.readSmallUleb128(); - LocalInfo localInfo = locals[register]; + boolean replaceLocalInTable = true; + LocalInfo localInfo; + if (register >= 0 && register < locals.length) { + localInfo = locals[register]; + } else { + localInfo = EMPTY_LOCAL_INFO; + replaceLocalInTable = false; + } + if (localInfo instanceof EndLocal) { localInfo = EMPTY_LOCAL_INFO; // don't replace the local info in locals. The new EndLocal won't have any info at all, @@ -216,11 +228,18 @@ public abstract class DebugInfo implements Iterable { } case DebugItemType.RESTART_LOCAL: { int register = reader.readSmallUleb128(); - LocalInfo localInfo = locals[register]; + LocalInfo localInfo; + if (register >= 0 && register < locals.length) { + localInfo = locals[register]; + } else { + localInfo = EMPTY_LOCAL_INFO; + } ImmutableRestartLocal restartLocal = new ImmutableRestartLocal(codeAddress, register, localInfo.getName(), localInfo.getType(), localInfo.getSignature()); - locals[register] = restartLocal; + if (register >= 0 && register < locals.length) { + locals[register] = restartLocal; + } return restartLocal; } case DebugItemType.PROLOGUE_END: { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/OneFixedFourParameterRegisterInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/DualReferenceInstruction.java similarity index 74% rename from dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/OneFixedFourParameterRegisterInstruction.java rename to dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/DualReferenceInstruction.java index c03bff77..0f1f81b2 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/OneFixedFourParameterRegisterInstruction.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 @@ -31,17 +31,11 @@ package org.jf.dexlib2.iface.instruction; -public interface OneFixedFourParameterRegisterInstruction extends VariableRegisterInstruction { - int getRegisterFixedC(); - int getRegisterParameterD(); - int getRegisterParameterE(); - int getRegisterParameterF(); - int getRegisterParameterG(); +import org.jf.dexlib2.iface.reference.Reference; - /** Returns the count of just the parameter register counts; in range of [0, 4] */ - int getParameterRegisterCount(); +import javax.annotation.Nonnull; - /** Includes the total sum of both fixed and parameter register counts; at least 1 */ - @Override - int getRegisterCount(); +public interface DualReferenceInstruction extends ReferenceInstruction { + @Nonnull Reference getReference2(); + int getReferenceType2(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.java similarity index 86% rename from dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction25x.java rename to dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.java index 51df2dee..221fd623 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction25x.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction45cc.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 @@ -31,7 +31,8 @@ package org.jf.dexlib2.iface.instruction.formats; -import org.jf.dexlib2.iface.instruction.OneFixedFourParameterRegisterInstruction; +import org.jf.dexlib2.iface.instruction.DualReferenceInstruction; +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction; -public interface Instruction25x extends OneFixedFourParameterRegisterInstruction { +public interface Instruction45cc extends FiveRegisterInstruction, DualReferenceInstruction { } diff --git a/baksmali/src/test/java/org/jf/baksmali/LambdaTest.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.java similarity index 72% rename from baksmali/src/test/java/org/jf/baksmali/LambdaTest.java rename to dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.java index 9dd3237f..d0b930b1 100644 --- a/baksmali/src/test/java/org/jf/baksmali/LambdaTest.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/instruction/formats/Instruction4rcc.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,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.jf.baksmali; +package org.jf.dexlib2.iface.instruction.formats; -import org.junit.Test; +import org.jf.dexlib2.iface.instruction.DualReferenceInstruction; +import org.jf.dexlib2.iface.instruction.RegisterRangeInstruction; -public class LambdaTest extends IdenticalRoundtripTest { - - private BaksmaliOptions createOptions() { - BaksmaliOptions options = new BaksmaliOptions(); - options.apiLevel = 23; // since we need at least level 23 for lambda opcodes - options.experimentalOpcodes = true; // since these opcodes aren't implemented in runtime yet); - return options; - } - - @Test - public void testHelloWorldLambda() { - runTest("HelloWorldLambda", createOptions()); - } +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/ImmutableInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java index ed50ef5b..432f1930 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction.java @@ -97,8 +97,6 @@ public abstract class ImmutableInstruction implements Instruction { return ImmutableInstruction22x.of((Instruction22x)instruction); case Format23x: return ImmutableInstruction23x.of((Instruction23x)instruction); - case Format25x: - return ImmutableInstruction25x.of((Instruction25x) instruction); case Format30t: return ImmutableInstruction30t.of((Instruction30t)instruction); case Format31c: diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction25x.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction25x.java deleted file mode 100644 index 2f31eaea..00000000 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/instruction/ImmutableInstruction25x.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2015, 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.instruction; - -import org.jf.dexlib2.Format; -import org.jf.dexlib2.Opcode; -import org.jf.dexlib2.iface.instruction.formats.Instruction25x; -import org.jf.dexlib2.util.Preconditions; - -import javax.annotation.Nonnull; - -public class ImmutableInstruction25x extends ImmutableInstruction implements Instruction25x { - public static final Format FORMAT = Format.Format25x; - - protected final int parameterRegisterCount; - protected final int registerClosure; - protected final int registerD; - protected final int registerE; - protected final int registerF; - protected final int registerG; - - public ImmutableInstruction25x(@Nonnull Opcode opcode, - int parameterRegisterCount, - int registerClosure, - int registerD, - int registerE, - int registerF, - int registerG) { - super(opcode); - this.parameterRegisterCount = - Preconditions.check25xParameterRegisterCount(parameterRegisterCount); - this.registerClosure = Preconditions.checkNibbleRegister(registerClosure); - this.registerD = (parameterRegisterCount>0) ? - Preconditions.checkNibbleRegister(registerD) : 0; - this.registerE = (parameterRegisterCount>1) ? - Preconditions.checkNibbleRegister(registerE) : 0; - this.registerF = (parameterRegisterCount>2) ? - Preconditions.checkNibbleRegister(registerF) : 0; - this.registerG = (parameterRegisterCount>3) ? - Preconditions.checkNibbleRegister(registerG) : 0; - } - - public static ImmutableInstruction25x of(Instruction25x instruction) { - if (instruction instanceof ImmutableInstruction25x) { - return (ImmutableInstruction25x)instruction; - } - return new ImmutableInstruction25x( - instruction.getOpcode(), - instruction.getRegisterCount(), - instruction.getRegisterFixedC(), - instruction.getRegisterParameterD(), - instruction.getRegisterParameterE(), - instruction.getRegisterParameterF(), - instruction.getRegisterParameterG()); - } - - - @Override public int getParameterRegisterCount() { return parameterRegisterCount; } - @Override public int getRegisterCount() { return parameterRegisterCount + 1; } - - @Override public int getRegisterFixedC() { return registerClosure; } - @Override public int getRegisterParameterD() { return registerD; } - @Override public int getRegisterParameterE() { return registerE; } - @Override public int getRegisterParameterF() { return registerF; } - @Override public int getRegisterParameterG() { return registerG; } - - @Override public Format getFormat() { return FORMAT; } -} 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..2f9fe2d7 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)); @@ -133,15 +133,6 @@ public class Preconditions { return registerCount; } - public static int check25xParameterRegisterCount(int registerCount) { - if (registerCount < 0 || registerCount > 4) { - throw new IllegalArgumentException( - String.format("Invalid parameter register count: %d. " + - "Must be between 0 and 4, inclusive.", registerCount)); - } - return registerCount; - } - public static int checkRegisterRangeCount(int registerCount) { if ((registerCount & 0xFFFFFF00) != 0) { throw new IllegalArgumentException( 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..6ca1ce93 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) { @@ -1005,9 +1006,6 @@ public abstract class DexWriter< case Format23x: instructionWriter.write((Instruction23x)instruction); break; - case Format25x: - instructionWriter.write((Instruction25x)instruction); - break; case Format30t: instructionWriter.write((Instruction30t)instruction); break; @@ -1029,6 +1027,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..1b883f1f 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) { @@ -334,19 +343,6 @@ 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/examples/HelloWorldLambda/HelloWorldFunctionalInterface.smali b/examples/HelloWorldLambda/HelloWorldFunctionalInterface.smali deleted file mode 100644 index c2ada47d..00000000 --- a/examples/HelloWorldLambda/HelloWorldFunctionalInterface.smali +++ /dev/null @@ -1,8 +0,0 @@ -# Functional interface used by HelloWorld.smali -# Required in order to reify the lambda with create-lambda or unbox-lambda instructions - -.class public abstract interface LHelloWorldFunctionalInterface; -.super Ljava/lang/Object; - -.method public abstract applyFourStrings(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V -.end method diff --git a/examples/HelloWorldLambda/HelloWorldLambda.smali b/examples/HelloWorldLambda/HelloWorldLambda.smali deleted file mode 100644 index 36c8e49c..00000000 --- a/examples/HelloWorldLambda/HelloWorldLambda.smali +++ /dev/null @@ -1,57 +0,0 @@ -.class public LHelloWorldLambda; - -#Ye olde hello world application (with lambdas!) -#To assemble and run this on a phone or emulator: -# -#java -jar smali.jar -o classes.dex HelloWorldLambda.smali HelloWorldFunctionalInterface.smali -#zip HelloWorld.zip classes.dex -#adb push HelloWorld.zip /data/local -#adb shell dalvikvm -cp /data/local/HelloWorld.zip HelloWorld -# -#if you get out of memory type errors when running smali.jar, try -#java -Xmx512m -jar smali.jar HelloWorldLambda.smali -#instead - -.super Ljava/lang/Object; - -.method public static main([Ljava/lang/String;)V - .registers 9 # 1 parameter, 8 locals - - sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; - - const-string v1, "Hello World!" - const-string v2, "How" # vD - const-string v3, "are" # vE - const-string v4, "you" # vF - const-string v5, "doing?" # vG - - capture-variable v1, "helloworld" - - # TODO: do I need to pass the type of the lambda's functional interface here as a type id? - create-lambda v1, LHelloWorldLambda;->doHelloWorld(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - # Method descriptor is not required here, because only the single-abstract method is ever invoked. - invoke-lambda v1, {v2, v3, v4, v5} - - box-lambda v6, v1 # The type of v6 is now 'LHelloWorldFunctionalInterface;' - invoke-virtual {v6, v2, v3, v4, v5}, LHelloWorldFunctionalInterface;->applyFourStrings(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - - # FIXME: should be \HelloWorldFunctionalInterface; instead of L...; - - # TODO: do we really need the type descriptor here at all? - unbox-lambda v7, v6, LHelloWorldFunctionalInterface; # The type of v7 is now \HelloWorldFunctionalInterface; - invoke-lambda v7, {v2, v3, v4, v5} - - return-void -.end method - -.method public static doHelloWorld(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - .registers 6 # 4 parameters, 2 locals - - # This helloworld variable is brought to you by the variable liberation front - liberate-variable v0, p0, "helloworld" - - sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; - invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V - - return-void -.end method diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 085a1cdc..5ccda13e 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 692d204c..23bc0f51 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Feb 14 12:35:03 PST 2016 +#Fri Jul 08 16:46:58 PDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip diff --git a/gradlew b/gradlew index 91a7e269..9d82f789 100755 --- a/gradlew +++ b/gradlew @@ -42,11 +42,6 @@ case "`uname`" in ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do fi done SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- +cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" -cd "$SAVED" >&- +cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -114,6 +109,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/gradlew.bat b/gradlew.bat index aec99730..72d362da 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -46,7 +46,7 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args diff --git a/smali/build.gradle b/smali/build.gradle index 857812a1..1cbe3546 100644 --- a/smali/build.gradle +++ b/smali/build.gradle @@ -30,7 +30,7 @@ */ apply plugin: 'antlr' -apply plugin: 'jflex' +apply plugin: 'org.xbib.gradle.plugin.jflex' buildscript { repositories { @@ -46,10 +46,6 @@ configurations { // Remove the full antlr library that's added by the antlr plugin. We manually // add the smaller antlr_runtime library instead compile.exclude group: 'org.antlr', module: 'antlr' - - // The jflex lexer doesn't have any runtime dependencies, so remove the dependency - // that gets added by the jflex plugin - compile.exclude group: 'de.jflex', module: 'jflex' } sourceSets { @@ -86,7 +82,6 @@ dependencies { testCompile depends.junit antlr depends.antlr - jflex depends.jflex } processResources.inputs.property('version', version) @@ -119,8 +114,8 @@ generateGrammarSource { outputDirectory = new File(outputDirectory, 'org/jf/smali') } -generateJFlexSource { - outputDirectory = new File(outputDirectory, 'org/jf/smali') +jflex { + generateDir = new File(generateDir, 'org/jf/smali') } uploadArchives { diff --git a/smali/src/main/antlr/smaliParser.g b/smali/src/main/antlr/smaliParser.g index fcccbe80..29cd141b 100644 --- a/smali/src/main/antlr/smaliParser.g +++ b/smali/src/main/antlr/smaliParser.g @@ -86,8 +86,6 @@ tokens { INSTRUCTION_FORMAT21c_FIELD_ODEX; INSTRUCTION_FORMAT21c_STRING; INSTRUCTION_FORMAT21c_TYPE; - INSTRUCTION_FORMAT21c_LAMBDA; - INSTRUCTION_FORMAT21c_METHOD; INSTRUCTION_FORMAT21ih; INSTRUCTION_FORMAT21lh; INSTRUCTION_FORMAT21s; @@ -96,14 +94,12 @@ tokens { INSTRUCTION_FORMAT22c_FIELD; INSTRUCTION_FORMAT22c_FIELD_ODEX; INSTRUCTION_FORMAT22c_TYPE; - INSTRUCTION_FORMAT22c_STRING; INSTRUCTION_FORMAT22cs_FIELD; INSTRUCTION_FORMAT22s; INSTRUCTION_FORMAT22s_OR_ID; INSTRUCTION_FORMAT22t; INSTRUCTION_FORMAT22x; INSTRUCTION_FORMAT23x; - INSTRUCTION_FORMAT25x; INSTRUCTION_FORMAT30t; INSTRUCTION_FORMAT31c; INSTRUCTION_FORMAT31i; @@ -120,6 +116,8 @@ tokens { INSTRUCTION_FORMAT3rc_TYPE; INSTRUCTION_FORMAT3rmi_METHOD; INSTRUCTION_FORMAT3rms_METHOD; + INSTRUCTION_FORMAT45cc_METHOD; + INSTRUCTION_FORMAT4rcc_METHOD; INSTRUCTION_FORMAT51l; LINE_COMMENT; LINE_DIRECTIVE; @@ -210,8 +208,6 @@ tokens { I_STATEMENT_FORMAT21c_TYPE; I_STATEMENT_FORMAT21c_FIELD; I_STATEMENT_FORMAT21c_STRING; - I_STATEMENT_FORMAT21c_LAMBDA; - I_STATEMENT_FORMAT21c_METHOD; I_STATEMENT_FORMAT21ih; I_STATEMENT_FORMAT21lh; I_STATEMENT_FORMAT21s; @@ -219,12 +215,10 @@ tokens { I_STATEMENT_FORMAT22b; I_STATEMENT_FORMAT22c_FIELD; I_STATEMENT_FORMAT22c_TYPE; - I_STATEMENT_FORMAT22c_STRING; I_STATEMENT_FORMAT22s; I_STATEMENT_FORMAT22t; I_STATEMENT_FORMAT22x; I_STATEMENT_FORMAT23x; - I_STATEMENT_FORMAT25x; I_STATEMENT_FORMAT30t; I_STATEMENT_FORMAT31c; I_STATEMENT_FORMAT31i; @@ -234,6 +228,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; @@ -562,18 +558,14 @@ simple_name | INSTRUCTION_FORMAT21c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD_ODEX] | INSTRUCTION_FORMAT21c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_STRING] | INSTRUCTION_FORMAT21c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_TYPE] - | INSTRUCTION_FORMAT21c_LAMBDA -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_LAMBDA] - | INSTRUCTION_FORMAT21c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_METHOD] | INSTRUCTION_FORMAT21t -> SIMPLE_NAME[$INSTRUCTION_FORMAT21t] | INSTRUCTION_FORMAT22c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD] | INSTRUCTION_FORMAT22c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD_ODEX] | INSTRUCTION_FORMAT22c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_TYPE] - | INSTRUCTION_FORMAT22c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_STRING] | INSTRUCTION_FORMAT22cs_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22cs_FIELD] | INSTRUCTION_FORMAT22s_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT22s_OR_ID] | INSTRUCTION_FORMAT22t -> SIMPLE_NAME[$INSTRUCTION_FORMAT22t] | INSTRUCTION_FORMAT23x -> SIMPLE_NAME[$INSTRUCTION_FORMAT23x] - | INSTRUCTION_FORMAT25x -> SIMPLE_NAME[$INSTRUCTION_FORMAT25x] | INSTRUCTION_FORMAT31i_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT31i_OR_ID] | INSTRUCTION_FORMAT31t -> SIMPLE_NAME[$INSTRUCTION_FORMAT31t] | INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD] @@ -581,6 +573,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 @@ -817,8 +811,6 @@ instruction | insn_format21c_field_odex | insn_format21c_string | insn_format21c_type - | insn_format21c_lambda - | insn_format21c_method | insn_format21ih | insn_format21lh | insn_format21s @@ -827,13 +819,11 @@ instruction | insn_format22c_field | insn_format22c_field_odex | insn_format22c_type - | insn_format22c_string | insn_format22cs_field | insn_format22s | insn_format22t | insn_format22x | insn_format23x - | insn_format25x | insn_format30t | insn_format31c | insn_format31i @@ -849,6 +839,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 @@ -927,16 +919,6 @@ insn_format21c_type INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA nonvoid_type_descriptor -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor); -insn_format21c_lambda - : //e.g. capture-variable v1, "foobar" - INSTRUCTION_FORMAT21c_LAMBDA REGISTER COMMA STRING_LITERAL - -> ^(I_STATEMENT_FORMAT21c_LAMBDA[$start, "I_STATEMENT_FORMAT21c_LAMBDA"] INSTRUCTION_FORMAT21c_LAMBDA REGISTER STRING_LITERAL); - -insn_format21c_method - : //e.g. create-lambda v1, java/io/PrintStream/print(Ljava/lang/Stream;)V - INSTRUCTION_FORMAT21c_METHOD REGISTER COMMA method_reference - -> ^(I_STATEMENT_FORMAT21c_METHOD[$start, "I_STATEMENT_FORMAT21c_METHOD"] INSTRUCTION_FORMAT21c_METHOD REGISTER method_reference); - insn_format21ih : //e.g. const/high16 v1, 1234 INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal @@ -982,11 +964,6 @@ insn_format22c_type INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor); -insn_format22c_string - : //e.g. liberate-variable v0, v1, "baz" - INSTRUCTION_FORMAT22c_STRING REGISTER COMMA REGISTER COMMA STRING_LITERAL - -> ^(I_STATEMENT_FORMAT22c_STRING[$start, "I_STATEMENT_FORMAT22c_STRING"] INSTRUCTION_FORMAT22c_STRING REGISTER REGISTER STRING_LITERAL); - insn_format22cs_field : //e.g. iget-quick v0, v1, field@0xc INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET @@ -1014,11 +991,6 @@ insn_format23x INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER -> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER); -insn_format25x - : //e.g. invoke-lambda vClosure, {vA, vB, vC, vD} -- up to 4 parameters + the closure. - INSTRUCTION_FORMAT25x REGISTER COMMA OPEN_BRACE register_list CLOSE_BRACE - -> ^(I_STATEMENT_FORMAT25x[$start, "I_STATEMENT_FORMAT25x"] INSTRUCTION_FORMAT25x REGISTER register_list); - insn_format30t : //e.g. goto/32 endloop: INSTRUCTION_FORMAT30t label_ref @@ -1106,6 +1078,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 +1123,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..d074579b 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.*; @@ -674,22 +675,6 @@ register_list returns[byte[\] registers, byte registerCount] $registers[$registerCount++] = parseRegister_nibble($REGISTER.text); })*); -register_list4 returns[byte[\] registers, byte registerCount] - @init - { - $registers = new byte[4]; - $registerCount = 0; - } - : ^(I_REGISTER_LIST - (REGISTER - { - if ($registerCount == 4) { - throw new SemanticException(input, $I_REGISTER_LIST, "A list4 of registers can only have a maximum of 4 " + - "registers. Use the /range alternate opcode instead."); - } - $registers[$registerCount++] = parseRegister_nibble($REGISTER.text); - })*); - register_range returns[int startRegister, int endRegister] : ^(I_REGISTER_RANGE (startReg=REGISTER endReg=REGISTER?)?) { @@ -742,8 +727,6 @@ instruction | insn_format21c_field | insn_format21c_string | insn_format21c_type - | insn_format21c_lambda - | insn_format21c_method | insn_format21ih | insn_format21lh | insn_format21s @@ -751,12 +734,10 @@ instruction | insn_format22b | insn_format22c_field | insn_format22c_type - | insn_format22c_string | insn_format22s | insn_format22t | insn_format22x | insn_format23x - | insn_format25x | insn_format30t | insn_format31c | insn_format31i @@ -766,6 +747,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 @@ -881,30 +864,6 @@ insn_format21c_type dexBuilder.internTypeReference($nonvoid_type_descriptor.type))); }; -insn_format21c_lambda - : //e.g. capture-variable v1, "foobar" - ^(I_STATEMENT_FORMAT21c_LAMBDA INSTRUCTION_FORMAT21c_LAMBDA REGISTER string_literal) - { - Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_LAMBDA.text); - short regA = parseRegister_byte($REGISTER.text); - - $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA, - dexBuilder.internStringReference($string_literal.value))); - }; - -insn_format21c_method - : //e.g. create-lambda v1, java/io/PrintStream/print(Ljava/lang/Stream;)V - ^(I_STATEMENT_FORMAT21c_METHOD INSTRUCTION_FORMAT21c_METHOD REGISTER method_reference) - { - Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_METHOD.text); - short regA = parseRegister_byte($REGISTER.text); - - ImmutableMethodReference methodReference = $method_reference.methodReference; - - $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA, - dexBuilder.internMethodReference(methodReference))); - }; - insn_format21ih : //e.g. const/high16 v1, 1234 ^(I_STATEMENT_FORMAT21ih INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal) @@ -991,18 +950,6 @@ insn_format22c_type dexBuilder.internTypeReference($nonvoid_type_descriptor.type))); }; -insn_format22c_string - : //e.g. liberate-variable v0, v1, "baz" - ^(I_STATEMENT_FORMAT22c_STRING INSTRUCTION_FORMAT22c_STRING registerA=REGISTER registerB=REGISTER string_literal) - { - Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_STRING.text); - byte regA = parseRegister_nibble($registerA.text); - byte regB = parseRegister_nibble($registerB.text); - - $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB, - dexBuilder.internStringReference($string_literal.value))); - }; - insn_format22s : //e.g. add-int/lit16 v0, v1, 12345 ^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal) @@ -1050,23 +997,6 @@ insn_format23x $method::methodBuilder.addInstruction(new BuilderInstruction23x(opcode, regA, regB, regC)); }; -insn_format25x - : //e.g. invoke-lambda vClosure, {vD, vE, vF, vG} -- up to 4 parameters + the closure. - ^(I_STATEMENT_FORMAT25x INSTRUCTION_FORMAT25x REGISTER register_list4) - { - Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT25x.text); - - byte closureRegister = parseRegister_nibble($REGISTER.text); - - //this depends on the fact that register_list4 returns a byte[4] - byte[] registers = $register_list4.registers; - int parameterRegisterCount = $register_list4.registerCount; // don't count closure register - - $method::methodBuilder.addInstruction(new BuilderInstruction25x(opcode, - parameterRegisterCount, closureRegister, registers[0], registers[1], - registers[2], registers[3])); - }; - insn_format30t : //e.g. goto/32 endloop: ^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t label_ref) @@ -1181,6 +1111,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..2cf3c869 100644 --- a/smali/src/main/jflex/smaliLexer.jflex +++ b/smali/src/main/jflex/smaliLexer.jflex @@ -476,14 +476,6 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | return newToken(INSTRUCTION_FORMAT21c_TYPE); } - "capture-variable" { // e.g. 'capture-variable vB, ' - return newToken(INSTRUCTION_FORMAT21c_LAMBDA); - } - - "create-lambda" { // e.g. 'create-lambda vClosure, ' - return newToken(INSTRUCTION_FORMAT21c_METHOD); - } - "const/high16" { return newToken(INSTRUCTION_FORMAT21ih); } @@ -515,14 +507,10 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | return newToken(INSTRUCTION_FORMAT22c_FIELD_ODEX); } - "instance-of" | "new-array" | "unbox-lambda" { + "instance-of" | "new-array" { return newToken(INSTRUCTION_FORMAT22c_TYPE); } - "liberate-variable" { - return newToken(INSTRUCTION_FORMAT22c_STRING); - } - "iget-quick" | "iget-wide-quick" | "iget-object-quick" | "iput-quick" | "iput-wide-quick" | "iput-object-quick" | "iput-boolean-quick" | "iput-byte-quick" | "iput-char-quick" | "iput-short-quick" { return newToken(INSTRUCTION_FORMAT22cs_FIELD); @@ -541,7 +529,7 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | return newToken(INSTRUCTION_FORMAT22t); } - "move/from16" | "move-wide/from16" | "move-object/from16" | "box-lambda" { + "move/from16" | "move-wide/from16" | "move-object/from16" { return newToken(INSTRUCTION_FORMAT22x); } @@ -555,10 +543,6 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | return newToken(INSTRUCTION_FORMAT23x); } - "invoke-lambda" { // e.g. invoke-lambda vClosure, {vD, vE, vF, vG} -- at most 4 params - return newToken(INSTRUCTION_FORMAT25x); - } - "goto/32" { return newToken(INSTRUCTION_FORMAT30t); } @@ -624,6 +608,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); } diff --git a/smali/src/test/java/ByteLiteralTest.java b/smali/src/test/java/org/jf/smali/ByteLiteralTest.java similarity index 77% rename from smali/src/test/java/ByteLiteralTest.java rename to smali/src/test/java/org/jf/smali/ByteLiteralTest.java index 2e6511da..7bf7c54e 100644 --- a/smali/src/test/java/ByteLiteralTest.java +++ b/smali/src/test/java/org/jf/smali/ByteLiteralTest.java @@ -1,32 +1,35 @@ /* - * [The "BSD licence"] - * Copyright (c) 2010 Ben Gruver (JesusFreke) + * 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: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * modification, are permitted provided that the following conditions are + * met: * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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, + * 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. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.jf.smali.LiteralTools; +package org.jf.smali;import org.jf.smali.LiteralTools; import org.junit.Assert; import org.junit.Test; diff --git a/smali/src/test/java/ImplicitReferenceTest.java b/smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java similarity index 97% rename from smali/src/test/java/ImplicitReferenceTest.java rename to smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java index b080c8a5..83046536 100644 --- a/smali/src/test/java/ImplicitReferenceTest.java +++ b/smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java @@ -1,18 +1,18 @@ /* - * Copyright 2014, Google Inc. + * 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 + * 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 + * 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 + * 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. * @@ -29,7 +29,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import com.google.common.collect.Lists; +package org.jf.smali;import com.google.common.collect.Lists; import com.google.common.collect.Maps; import junit.framework.Assert; import org.antlr.runtime.RecognitionException; diff --git a/smali/src/test/java/IntLiteralTest.java b/smali/src/test/java/org/jf/smali/IntLiteralTest.java similarity index 79% rename from smali/src/test/java/IntLiteralTest.java rename to smali/src/test/java/org/jf/smali/IntLiteralTest.java index f5a8c969..6cc7fbd6 100644 --- a/smali/src/test/java/IntLiteralTest.java +++ b/smali/src/test/java/org/jf/smali/IntLiteralTest.java @@ -1,32 +1,35 @@ /* - * [The "BSD licence"] - * Copyright (c) 2010 Ben Gruver (JesusFreke) + * 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: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * modification, are permitted provided that the following conditions are + * met: * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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, + * 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. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.jf.smali.LiteralTools; +package org.jf.smali;import org.jf.smali.LiteralTools; import org.junit.Assert; import org.junit.Test; diff --git a/smali/src/test/java/LexerTest.java b/smali/src/test/java/org/jf/smali/LexerTest.java similarity index 77% rename from smali/src/test/java/LexerTest.java rename to smali/src/test/java/org/jf/smali/LexerTest.java index d156015a..5f1f21e4 100644 --- a/smali/src/test/java/LexerTest.java +++ b/smali/src/test/java/org/jf/smali/LexerTest.java @@ -1,39 +1,38 @@ /* - * [The "BSD licence"] - * Copyright (c) 2010 Ben Gruver + * 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: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * modification, are permitted provided that the following conditions are + * met: * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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, + * 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. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.antlr.runtime.ANTLRInputStream; +package org.jf.smali;import org.antlr.runtime.ANTLRInputStream; import org.antlr.runtime.CommonToken; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.RecognitionException; -import org.jf.smali.expectedTokensTestGrammarLexer; -import org.jf.smali.expectedTokensTestGrammarParser; -import org.jf.smali.smaliFlexLexer; -import org.jf.smali.smaliParser; import org.junit.Assert; import org.junit.Test; @@ -135,9 +134,9 @@ public class LexerTest { String smaliFile = String.format("LexerTest%s%s.smali", File.separatorChar, test); String tokensFile = String.format("LexerTest%s%s.tokens", File.separatorChar, test); - expectedTokensTestGrammarLexer expectedTokensLexer = null; + org.jf.smali.expectedTokensTestGrammarLexer expectedTokensLexer = null; try { - expectedTokensLexer = new expectedTokensTestGrammarLexer(new ANTLRInputStream( + expectedTokensLexer = new org.jf.smali.expectedTokensTestGrammarLexer(new ANTLRInputStream( LexerTest.class.getClassLoader().getResourceAsStream(tokensFile))); } catch (IOException ex) { throw new RuntimeException(ex); @@ -145,8 +144,8 @@ public class LexerTest { CommonTokenStream expectedTokensStream = new CommonTokenStream(expectedTokensLexer); - expectedTokensTestGrammarParser expectedTokensParser = - new expectedTokensTestGrammarParser(expectedTokensStream); + org.jf.smali.expectedTokensTestGrammarParser expectedTokensParser = + new org.jf.smali.expectedTokensTestGrammarParser(expectedTokensStream); try { expectedTokensParser.top(); } catch (RecognitionException ex) { diff --git a/smali/src/test/java/LongLiteralTest.java b/smali/src/test/java/org/jf/smali/LongLiteralTest.java similarity index 80% rename from smali/src/test/java/LongLiteralTest.java rename to smali/src/test/java/org/jf/smali/LongLiteralTest.java index f68cf5a7..4659a0ba 100644 --- a/smali/src/test/java/LongLiteralTest.java +++ b/smali/src/test/java/org/jf/smali/LongLiteralTest.java @@ -1,32 +1,35 @@ /* - * [The "BSD licence"] - * Copyright (c) 2010 Ben Gruver (JesusFreke) + * 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: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * modification, are permitted provided that the following conditions are + * met: * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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, + * 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. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.jf.smali.LiteralTools; +package org.jf.smali;import org.jf.smali.LiteralTools; import org.junit.Assert; import org.junit.Test; diff --git a/smali/src/test/java/ShortLiteralTest.java b/smali/src/test/java/org/jf/smali/ShortLiteralTest.java similarity index 78% rename from smali/src/test/java/ShortLiteralTest.java rename to smali/src/test/java/org/jf/smali/ShortLiteralTest.java index e366be85..2ba22ac6 100644 --- a/smali/src/test/java/ShortLiteralTest.java +++ b/smali/src/test/java/org/jf/smali/ShortLiteralTest.java @@ -1,32 +1,35 @@ /* - * [The "BSD licence"] - * Copyright (c) 2010 Ben Gruver (JesusFreke) + * 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: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * modification, are permitted provided that the following conditions are + * met: * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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, + * 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. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.jf.smali.LiteralTools; +package org.jf.smali;import org.jf.smali.LiteralTools; import org.junit.Assert; import org.junit.Test; diff --git a/smali/src/test/resources/LexerTest/InstructionTest.smali b/smali/src/test/resources/LexerTest/InstructionTest.smali index 174cff8c..62e51006 100644 --- a/smali/src/test/resources/LexerTest/InstructionTest.smali +++ b/smali/src/test/resources/LexerTest/InstructionTest.smali @@ -85,8 +85,6 @@ const-string check-cast new-instance const-class -capture-variable -create-lambda const/high16 const-wide/high16 const/16 @@ -125,8 +123,6 @@ iput-wide-volatile iput-object-volatile instance-of new-array -unbox-lambda -liberate-variable iget-quick iget-wide-quick iget-object-quick @@ -153,7 +149,6 @@ if-le move/from16 move-wide/from16 move-object/from16 -box-lambda cmpl-float cmpg-float cmpl-double @@ -204,7 +199,6 @@ add-double sub-double mul-double div-double -invoke-lambda goto/32 const-string/jumbo const diff --git a/smali/src/test/resources/LexerTest/InstructionTest.tokens b/smali/src/test/resources/LexerTest/InstructionTest.tokens index fa959bad..dfbd584b 100644 --- a/smali/src/test/resources/LexerTest/InstructionTest.tokens +++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens @@ -85,8 +85,6 @@ INSTRUCTION_FORMAT21c_STRING("const-string") INSTRUCTION_FORMAT21c_TYPE("check-cast") INSTRUCTION_FORMAT21c_TYPE("new-instance") INSTRUCTION_FORMAT21c_TYPE("const-class") -INSTRUCTION_FORMAT21c_LAMBDA("capture-variable") -INSTRUCTION_FORMAT21c_METHOD("create-lambda") INSTRUCTION_FORMAT21ih("const/high16") INSTRUCTION_FORMAT21lh("const-wide/high16") INSTRUCTION_FORMAT21s("const/16") @@ -125,8 +123,6 @@ INSTRUCTION_FORMAT22c_FIELD_ODEX("iput-wide-volatile") INSTRUCTION_FORMAT22c_FIELD_ODEX("iput-object-volatile") INSTRUCTION_FORMAT22c_TYPE("instance-of") INSTRUCTION_FORMAT22c_TYPE("new-array") -INSTRUCTION_FORMAT22c_TYPE("unbox-lambda") -INSTRUCTION_FORMAT22c_STRING("liberate-variable") INSTRUCTION_FORMAT22cs_FIELD("iget-quick") INSTRUCTION_FORMAT22cs_FIELD("iget-wide-quick") INSTRUCTION_FORMAT22cs_FIELD("iget-object-quick") @@ -153,7 +149,6 @@ INSTRUCTION_FORMAT22t("if-le") INSTRUCTION_FORMAT22x("move/from16") INSTRUCTION_FORMAT22x("move-wide/from16") INSTRUCTION_FORMAT22x("move-object/from16") -INSTRUCTION_FORMAT22x("box-lambda") INSTRUCTION_FORMAT23x("cmpl-float") INSTRUCTION_FORMAT23x("cmpg-float") INSTRUCTION_FORMAT23x("cmpl-double") @@ -204,7 +199,6 @@ INSTRUCTION_FORMAT23x("add-double") INSTRUCTION_FORMAT23x("sub-double") INSTRUCTION_FORMAT23x("mul-double") INSTRUCTION_FORMAT23x("div-double") -INSTRUCTION_FORMAT25x("invoke-lambda") INSTRUCTION_FORMAT30t("goto/32") INSTRUCTION_FORMAT31c("const-string/jumbo") INSTRUCTION_FORMAT31i_OR_ID("const") diff --git a/smalidea/build.gradle b/smalidea/build.gradle index 6b855d7b..8cba19d2 100644 --- a/smalidea/build.gradle +++ b/smalidea/build.gradle @@ -93,7 +93,7 @@ if (!('idea' in gradle.startParameter.taskNames)) { apply plugin: 'org.jetbrains.intellij' intellij { - version 'IC-14.1.4' + version 'IC-15.0.6' pluginName 'smalidea' updateSinceUntilBuild false diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java deleted file mode 100644 index f822fd1f..00000000 --- a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2014, 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.smalidea.debugging; - -import com.intellij.debugger.actions.StepOverActionHandler; -import com.intellij.debugger.impl.DebuggerSession; -import com.intellij.debugger.ui.JavaDebuggerSupport; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.Project; -import com.intellij.xdebugger.impl.actions.DebuggerActionHandler; -import com.sun.jdi.request.StepRequest; -import org.jetbrains.annotations.NotNull; - -public class SmaliDebuggerSupport extends JavaDebuggerSupport { - private static boolean useModifiedMethod; - - static { - try { - DebuggerSession.class.getMethod("stepOver", boolean.class, int.class); - useModifiedMethod = true; - } catch (NoSuchMethodException ex) { - useModifiedMethod = false; - } - } - - private final StepOverActionHandler myStepOverActionHandler = new StepOverActionHandler() { - @Override - public void perform(@NotNull final Project project, AnActionEvent e) { - final DebuggerSession session = getSession(project); - - if (session != null) { - if (useModifiedMethod) { - session.stepOver(false, StepRequest.STEP_MIN); - } else { - session.stepOver(false); - } - } - } - - @Override public boolean isEnabled(@NotNull Project project, AnActionEvent event) { - // TODO: check if we're currently in a smali file? - return super.isEnabled(project, event); - } - }; - - @NotNull - @Override - public DebuggerActionHandler getStepOverHandler() { - return myStepOverActionHandler; - } - -} diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliSteppingCommandProvider.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliSteppingCommandProvider.java new file mode 100644 index 00000000..8c756810 --- /dev/null +++ b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliSteppingCommandProvider.java @@ -0,0 +1,63 @@ +/* + * 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.smalidea.debugging; + +import com.intellij.debugger.SourcePosition; +import com.intellij.debugger.engine.ContextUtil; +import com.intellij.debugger.engine.DebugProcessImpl.ResumeCommand; +import com.intellij.debugger.engine.SuspendContextImpl; +import com.intellij.debugger.engine.events.DebuggerCommandImpl; +import com.intellij.debugger.impl.JvmSteppingCommandProvider; +import com.sun.jdi.request.StepRequest; +import org.jetbrains.annotations.NotNull; +import org.jf.smalidea.SmaliLanguage; + +public class SmaliSteppingCommandProvider extends JvmSteppingCommandProvider { + @Override + public ResumeCommand getStepOverCommand(@NotNull final SuspendContextImpl suspendContext, boolean ignoreBreakpoints, + int stepSize) { + + final SourcePosition[] location = new SourcePosition[1]; + + suspendContext.getDebugProcess().getManagerThread().invokeAndWait(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { + location[0] = ContextUtil.getSourcePosition(suspendContext); + } + }) ; + + if (location[0] != null && location[0].getFile().getLanguage() == SmaliLanguage.INSTANCE) { + return suspendContext.getDebugProcess().createStepOverCommand(suspendContext, ignoreBreakpoints, + StepRequest.STEP_MIN); + } + return null; + } +} diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java index 746a629b..0eeb010b 100644 --- a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java +++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java @@ -102,13 +102,16 @@ public class LazyValue implements Value { } @Nullable - private T getNullableValue() { + protected T getNullableValue(boolean allowNull) { if (value == null) { try { if (evaluationContext == null) { final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext(); evaluationContext = debuggerContext.createEvaluationContext(); if (evaluationContext == null) { + if (!allowNull) { + throw new IllegalStateException("Can't create evaluation context"); + } return null; } } @@ -116,6 +119,9 @@ public class LazyValue implements Value { value = SmaliCodeFragmentFactory.evaluateRegister(evaluationContext, method, registerNumber, type); evaluationContext = null; } catch (EvaluateException ex) { + if (!allowNull) { + throw new IllegalStateException(ex); + } return null; } } @@ -124,7 +130,7 @@ public class LazyValue implements Value { @Nonnull protected T getValue() { - T value = getNullableValue(); + T value = getNullableValue(false); assert value != null; return value; } @@ -154,7 +160,7 @@ public class LazyValue implements Value { } @Override public boolean equals(Object obj) { - Value value = getNullableValue(); + Value value = getNullableValue(true); if (value != null) { return value.equals(obj); } @@ -162,7 +168,7 @@ public class LazyValue implements Value { } @Override public int hashCode() { - Value value = getNullableValue(); + Value value = getNullableValue(true); if (value != null) { return value.hashCode(); } @@ -170,7 +176,7 @@ public class LazyValue implements Value { } @Override public String toString() { - Value value = getNullableValue(); + Value value = getNullableValue(true); if (value != null) { return value.toString(); } diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java index 684293fa..c7e7321d 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java @@ -35,6 +35,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.intellij.debugger.SourcePosition; import com.intellij.lang.ASTNode; +import com.intellij.navigation.ItemPresentation; +import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -86,6 +88,10 @@ public class SmaliClass extends SmaliStubBasedPsiElement impleme return name.substring(lastDot+1); } + @Override public ItemPresentation getPresentation() { + return ItemPresentationProviders.getItemPresentation(this); + } + @Nullable @Override public String getQualifiedName() { SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT); if (classStatement == null) { diff --git a/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java b/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java index 305c7f8a..47cb08ca 100644 --- a/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java +++ b/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java @@ -32,6 +32,7 @@ package org.jf.smalidea.util; import com.google.common.collect.ImmutableMap; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.impl.ResolveScopeManager; @@ -129,6 +130,10 @@ public class NameUtils { public static PsiClass resolveSmaliType(@NotNull Project project, @NotNull GlobalSearchScope scope, @NotNull String smaliType) { + if (DumbService.isDumb(project)) { + return null; + } + JavaPsiFacade facade = JavaPsiFacade.getInstance(project); String javaType = NameUtils.smaliToJavaType(smaliType); diff --git a/smalidea/src/main/resources/META-INF/plugin.xml b/smalidea/src/main/resources/META-INF/plugin.xml index 6e24054b..8ae92dad 100644 --- a/smalidea/src/main/resources/META-INF/plugin.xml +++ b/smalidea/src/main/resources/META-INF/plugin.xml @@ -12,7 +12,7 @@ ]]> - + @@ -23,8 +23,7 @@ - + java/lang/Object;", "blah.smali"); + + Assert.assertNotNull(typeElement); + Assert.assertEquals("Object", typeElement.getName()); + + DumbServiceImpl.getInstance(getProject()).setDumb(true); + + PsiClass psiClass = typeElement.resolve(); + Assert.assertNull(psiClass); + + DumbServiceImpl.getInstance(getProject()).setDumb(false); + } + /** * Test a reference to a smali class from a smali class */ @@ -105,6 +124,8 @@ public class ClassReferenceTest extends ResolveTestCase { Assert.assertEquals("blarg", smaliClass.getQualifiedName()); } + + @Override protected Sdk getTestProjectJdk() { return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();