diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java index e609803b..bfb71e82 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java @@ -60,8 +60,8 @@ public class ReferenceFormatter { } writer.write(")@"); MethodHandleReference methodHandle = callSite.getMethodHandle(); - if (methodHandle.getMethodHandleType() != MethodHandleType.STATIC_INVOKE) { - throw new IllegalArgumentException("The linker method handle for a call site must be of type static-invoke"); + if (methodHandle.getMethodHandleType() != MethodHandleType.INVOKE_STATIC) { + throw new IllegalArgumentException("The linker method handle for a call site must be of type invoke-static"); } writeReference(writer, ReferenceType.METHOD, callSite.getMethodHandle().getMemberReference()); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/MethodHandleType.java b/dexlib2/src/main/java/org/jf/dexlib2/MethodHandleType.java index 91bd7231..72f1f78d 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/MethodHandleType.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/MethodHandleType.java @@ -31,52 +31,45 @@ package org.jf.dexlib2; -import com.google.common.collect.Maps; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; -import java.util.Map; public class MethodHandleType { public static final int STATIC_PUT = 0; public static final int STATIC_GET = 1; public static final int INSTANCE_PUT = 2; public static final int INSTANCE_GET = 3; - public static final int STATIC_INVOKE = 4; - public static final int INSTANCE_INVOKE = 5; + public static final int INVOKE_STATIC = 4; + public static final int INVOKE_INSTANCE = 5; + public static final int INVOKE_CONSTRUCTOR = 6; + public static final int INVOKE_DIRECT = 7; + public static final int INVOKE_INTERFACE = 8; - private static final Map methodHandleTypeNames = Maps.newHashMap(); - - static { - methodHandleTypeNames.put("static-put", STATIC_PUT); - methodHandleTypeNames.put("static-get", STATIC_GET); - methodHandleTypeNames.put("instance-put", INSTANCE_PUT); - methodHandleTypeNames.put("instance-get", INSTANCE_GET); - methodHandleTypeNames.put("static-invoke", STATIC_INVOKE); - methodHandleTypeNames.put("instance-invoke", INSTANCE_INVOKE); - } + private static final BiMap methodHandleTypeNames = new ImmutableBiMap.Builder() + .put(STATIC_PUT, "static-put") + .put(STATIC_GET, "static-get") + .put(INSTANCE_PUT, "instance-put") + .put(INSTANCE_GET, "instance-get") + .put(INVOKE_STATIC, "invoke-static") + .put(INVOKE_INSTANCE, "invoke-instance") + .put(INVOKE_CONSTRUCTOR, "invoke-constructor") + .put(INVOKE_DIRECT, "invoke-direct") + .put(INVOKE_INTERFACE, "invoke-interface") + .build(); @Nonnull public static String toString(int methodHandleType) { - switch (methodHandleType) { - case STATIC_PUT: - return "static-put"; - case STATIC_GET: - return "static-get"; - case INSTANCE_PUT: - return "instance-put"; - case INSTANCE_GET: - return "instance-get"; - case STATIC_INVOKE: - return "static-invoke"; - case INSTANCE_INVOKE: - return "instance-invoke"; - default: - throw new InvalidMethodHandleTypeException(methodHandleType); + String val = methodHandleTypeNames.get(methodHandleType); + if (val == null) { + throw new InvalidMethodHandleTypeException(methodHandleType); } + return val; } public static int getMethodHandleType(String methodHandleType) { - Integer ret = methodHandleTypeNames.get(methodHandleType); + Integer ret = methodHandleTypeNames.inverse().get(methodHandleType); if (ret == null) { throw new ExceptionWithContext("Invalid method handle type: %s", methodHandleType); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java index 11c8cc10..461639e4 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/MethodHandleItem.java @@ -34,6 +34,7 @@ package org.jf.dexlib2.dexbacked.raw; import org.jf.dexlib2.MethodHandleType; import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; import org.jf.dexlib2.util.AnnotatedBytes; +import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -59,11 +60,22 @@ public class MethodHandleItem { int fieldOrMethodId = dexFile.readUshort(out.getCursor()); String fieldOrMethodDescriptor; - if (methodHandleType == MethodHandleType.STATIC_INVOKE || - methodHandleType == MethodHandleType.INSTANCE_INVOKE) { - fieldOrMethodDescriptor = MethodIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); - } else { - fieldOrMethodDescriptor = FieldIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); + switch (methodHandleType) { + case MethodHandleType.STATIC_PUT: + case MethodHandleType.STATIC_GET: + case MethodHandleType.INSTANCE_PUT: + case MethodHandleType.INSTANCE_GET: + fieldOrMethodDescriptor = FieldIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); + break; + case MethodHandleType.INVOKE_STATIC: + case MethodHandleType.INVOKE_INSTANCE: + case MethodHandleType.INVOKE_CONSTRUCTOR: + case MethodHandleType.INVOKE_DIRECT: + case MethodHandleType.INVOKE_INTERFACE: + fieldOrMethodDescriptor = MethodIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); + break; + default: + throw new ExceptionWithContext("Invalid method handle type: %d", methodHandleType); } out.annotate(2, "field_or_method_id = %s", fieldOrMethodDescriptor); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodHandleReference.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodHandleReference.java index 0e535e9a..005c39df 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodHandleReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/reference/DexBackedMethodHandleReference.java @@ -61,13 +61,16 @@ public class DexBackedMethodHandleReference extends BaseMethodHandleReference { public Reference getMemberReference() { int memberIndex = dexFile.readUshort(methodHandleOffset + MethodHandleItem.MEMBER_ID_OFFSET); switch (getMethodHandleType()) { - case MethodHandleType.INSTANCE_GET: - case MethodHandleType.INSTANCE_PUT: - case MethodHandleType.STATIC_GET: - case MethodHandleType.STATIC_PUT: + case MethodHandleType.STATIC_PUT: + case MethodHandleType.STATIC_GET: + case MethodHandleType.INSTANCE_PUT: + case MethodHandleType.INSTANCE_GET: return new DexBackedFieldReference(dexFile, memberIndex); - case MethodHandleType.INSTANCE_INVOKE: - case MethodHandleType.STATIC_INVOKE: + case MethodHandleType.INVOKE_STATIC: + case MethodHandleType.INVOKE_INSTANCE: + case MethodHandleType.INVOKE_CONSTRUCTOR: + case MethodHandleType.INVOKE_DIRECT: + case MethodHandleType.INVOKE_INTERFACE: return new DexBackedMethodReference(dexFile, memberIndex); default: throw new ExceptionWithContext("Invalid method handle type: %d", getMethodHandleType()); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodHandleReference.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodHandleReference.java index a7578f53..f9e0f1ee 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodHandleReference.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/reference/MethodHandleReference.java @@ -48,9 +48,6 @@ public interface MethodHandleReference extends Reference, Comparable Integer prev = internedItems.put(methodHandleReference, 0); if (prev == null) { switch (methodHandleReference.getMethodHandleType()) { - case MethodHandleType.INSTANCE_GET: - case MethodHandleType.INSTANCE_PUT: - case MethodHandleType.STATIC_GET: - case MethodHandleType.STATIC_PUT: + case MethodHandleType.STATIC_PUT: + case MethodHandleType.STATIC_GET: + case MethodHandleType.INSTANCE_PUT: + case MethodHandleType.INSTANCE_GET: dexPool.fieldSection.intern((FieldReference) methodHandleReference.getMemberReference()); break; - case MethodHandleType.INSTANCE_INVOKE: - case MethodHandleType.STATIC_INVOKE: + case MethodHandleType.INVOKE_STATIC: + case MethodHandleType.INVOKE_INSTANCE: + case MethodHandleType.INVOKE_CONSTRUCTOR: + case MethodHandleType.INVOKE_DIRECT: + case MethodHandleType.INVOKE_INTERFACE: dexPool.methodSection.intern((MethodReference) methodHandleReference.getMemberReference()); break; default: diff --git a/smali/src/main/antlr/smaliParser.g b/smali/src/main/antlr/smaliParser.g index 370c3dec..76de3bc5 100644 --- a/smali/src/main/antlr/smaliParser.g +++ b/smali/src/main/antlr/smaliParser.g @@ -110,6 +110,7 @@ tokens { INSTRUCTION_FORMAT35c_CALL_SITE; INSTRUCTION_FORMAT35c_METHOD; INSTRUCTION_FORMAT35c_METHOD_ODEX; + INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE; INSTRUCTION_FORMAT35c_TYPE; INSTRUCTION_FORMAT35mi_METHOD; INSTRUCTION_FORMAT35ms_METHOD; @@ -586,6 +587,7 @@ simple_name | INSTRUCTION_FORMAT35c_CALL_SITE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_CALL_SITE] | INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD] | INSTRUCTION_FORMAT35c_METHOD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD_ODEX] + | INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE] | INSTRUCTION_FORMAT35c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_TYPE] | INSTRUCTION_FORMAT35mi_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35mi_METHOD] | INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD] @@ -724,7 +726,8 @@ call_site_reference method_handle_reference : METHOD_HANDLE_TYPE_FIELD AT field_reference -> METHOD_HANDLE_TYPE_FIELD field_reference - | METHOD_HANDLE_TYPE_METHOD AT method_reference -> METHOD_HANDLE_TYPE_METHOD method_reference; + | METHOD_HANDLE_TYPE_METHOD AT method_reference -> METHOD_HANDLE_TYPE_METHOD method_reference + | INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE AT method_reference -> INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE method_reference; method_handle_literal : method_handle_reference @@ -826,6 +829,10 @@ instruction_format22s instruction_format31i : INSTRUCTION_FORMAT31i | INSTRUCTION_FORMAT31i_OR_ID -> INSTRUCTION_FORMAT31i[$INSTRUCTION_FORMAT31i_OR_ID]; + +instruction_format35c_method + : INSTRUCTION_FORMAT35c_METHOD + | INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE -> INSTRUCTION_FORMAT35c_METHOD[$INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE]; instruction : insn_format10t @@ -943,7 +950,7 @@ insn_format21c_field_odex -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER field_reference); insn_format21c_method_handle - : //e.g. const-method-handle v0, static-invoke@Ljava/lang/Integer;->toString(I)Ljava/lang/String; + : //e.g. const-method-handle v0, invoke-static@Ljava/lang/Integer;->toString(I)Ljava/lang/String; INSTRUCTION_FORMAT21c_METHOD_HANDLE REGISTER COMMA method_handle_reference -> ^(I_STATEMENT_FORMAT21c_METHOD_HANDLE[$start, "I_STATEMENT_FORMAT21c_METHOD_HANDLE"] INSTRUCTION_FORMAT21c_METHOD_HANDLE REGISTER method_handle_reference); @@ -1069,8 +1076,8 @@ insn_format35c_call_site insn_format35c_method : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V - INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA method_reference - -> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list method_reference); + instruction_format35c_method OPEN_BRACE register_list CLOSE_BRACE COMMA method_reference + -> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] instruction_format35c_method register_list method_reference); insn_format35c_type : //e.g. filled-new-array {v0,v1}, I diff --git a/smali/src/main/antlr/smaliTreeWalker.g b/smali/src/main/antlr/smaliTreeWalker.g index 5844bb45..f3595232 100644 --- a/smali/src/main/antlr/smaliTreeWalker.g +++ b/smali/src/main/antlr/smaliTreeWalker.g @@ -514,7 +514,7 @@ call_site_reference returns[ImmutableCallSiteReference callSiteReference] { String callSiteName = $call_site_name.text; ImmutableMethodHandleReference methodHandleReference = - new ImmutableMethodHandleReference(MethodHandleType.STATIC_INVOKE, + new ImmutableMethodHandleReference(MethodHandleType.INVOKE_STATIC, $method_reference.methodReference); $callSiteReference = new ImmutableCallSiteReference( callSiteName, methodHandleReference, $method_name.value, $method_prototype.proto, @@ -522,7 +522,7 @@ call_site_reference returns[ImmutableCallSiteReference callSiteReference] }; method_handle_type returns[int methodHandleType] - : METHOD_HANDLE_TYPE_FIELD | METHOD_HANDLE_TYPE_METHOD { + : (METHOD_HANDLE_TYPE_FIELD | METHOD_HANDLE_TYPE_METHOD | INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE) { $methodHandleType = MethodHandleType.getMethodHandleType($text); }; @@ -891,7 +891,7 @@ insn_format21c_field }; insn_format21c_method_handle - : //e.g. const-method-handle v0, static-invoke@Ljava/lang/Integer;->toString(I)Ljava/lang/String; + : //e.g. const-method-handle v0, invoke-static@Ljava/lang/Integer;->toString(I)Ljava/lang/String; ^(I_STATEMENT_FORMAT21c_METHOD_HANDLE inst=(INSTRUCTION_FORMAT21c_METHOD_HANDLE) REGISTER method_handle_reference) { Opcode opcode = opcodes.getOpcodeByName($inst.text); diff --git a/smali/src/main/jflex/smaliLexer.jflex b/smali/src/main/jflex/smaliLexer.jflex index 7e6c1c1c..1bae56e1 100644 --- a/smali/src/main/jflex/smaliLexer.jflex +++ b/smali/src/main/jflex/smaliLexer.jflex @@ -409,11 +409,11 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | "vtable@0x" {HexDigit}+ { return newToken(VTABLE_INDEX); } "field@0x" {HexDigit}+ { return newToken(FIELD_OFFSET); } - "instance-get" | "instance-put" | "static-get" | "static-put" { + "static-put" | "static-get" | "instance-put" | "instance-get" { return newToken(METHOD_HANDLE_TYPE_FIELD); } - "instance-invoke" | "static-invoke" { + "invoke-instance" | "invoke-constructor" { return newToken(METHOD_HANDLE_TYPE_METHOD); } @@ -588,9 +588,13 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | return newToken(INSTRUCTION_FORMAT35c_CALL_SITE); } - "invoke-virtual" | "invoke-super" | "invoke-direct" | "invoke-static" | "invoke-interface" { + "invoke-virtual" | "invoke-super" { return newToken(INSTRUCTION_FORMAT35c_METHOD); } + + "invoke-direct" | "invoke-static" | "invoke-interface" { + return newToken(INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE); + } "invoke-direct-empty" { return newToken(INSTRUCTION_FORMAT35c_METHOD_ODEX);