1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dex;
18 
19 import com.android.dex.Dex.Section;
20 import com.android.dex.util.Unsigned;
21 
22 /**
23  * A method_handle_item:
24  * https://source.android.com/devices/tech/dalvik/dex-format#method-handle-item
25  */
26 public class MethodHandle implements Comparable<MethodHandle> {
27 
28     /**
29      * A method handle type code:
30      * https://source.android.com/devices/tech/dalvik/dex-format#method-handle-type-codes
31      */
32     public enum MethodHandleType {
33         METHOD_HANDLE_TYPE_STATIC_PUT(0x00),
34         METHOD_HANDLE_TYPE_STATIC_GET(0x01),
35         METHOD_HANDLE_TYPE_INSTANCE_PUT(0x02),
36         METHOD_HANDLE_TYPE_INSTANCE_GET(0x03),
37         METHOD_HANDLE_TYPE_INVOKE_STATIC(0x04),
38         METHOD_HANDLE_TYPE_INVOKE_INSTANCE(0x05),
39         METHOD_HANDLE_TYPE_INVOKE_DIRECT(0x06),
40         METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR(0x07),
41         METHOD_HANDLE_TYPE_INVOKE_INTERFACE(0x08);
42 
43         private final int value;
44 
MethodHandleType(int value)45         MethodHandleType(int value) {
46             this.value = value;
47         }
48 
fromValue(int value)49         static MethodHandleType fromValue(int value) {
50             for (MethodHandleType methodHandleType : values()) {
51                 if (methodHandleType.value == value) {
52                     return methodHandleType;
53                 }
54             }
55             throw new IllegalArgumentException(String.valueOf(value));
56         }
57 
isField()58         public boolean isField() {
59             switch (this) {
60                 case METHOD_HANDLE_TYPE_STATIC_PUT:
61                 case METHOD_HANDLE_TYPE_STATIC_GET:
62                 case METHOD_HANDLE_TYPE_INSTANCE_PUT:
63                 case METHOD_HANDLE_TYPE_INSTANCE_GET:
64                     return true;
65                 default:
66                     return false;
67             }
68         }
69     }
70 
71     private final Dex dex;
72     private final MethodHandleType methodHandleType;
73     private final int unused1;
74     private final int fieldOrMethodId;
75     private final int unused2;
76 
MethodHandle( Dex dex, MethodHandleType methodHandleType, int unused1, int fieldOrMethodId, int unused2)77     public MethodHandle(
78             Dex dex,
79             MethodHandleType methodHandleType,
80             int unused1,
81             int fieldOrMethodId,
82             int unused2) {
83         this.dex = dex;
84         this.methodHandleType = methodHandleType;
85         this.unused1 = unused1;
86         this.fieldOrMethodId = fieldOrMethodId;
87         this.unused2 = unused2;
88     }
89 
90     @Override
compareTo(MethodHandle o)91     public int compareTo(MethodHandle o) {
92         if (methodHandleType != o.methodHandleType) {
93             return methodHandleType.compareTo(o.methodHandleType);
94         }
95         return Unsigned.compare(fieldOrMethodId, o.fieldOrMethodId);
96     }
97 
getMethodHandleType()98     public MethodHandleType getMethodHandleType() {
99         return methodHandleType;
100     }
101 
getUnused1()102     public int getUnused1() {
103         return unused1;
104     }
105 
getFieldOrMethodId()106     public int getFieldOrMethodId() {
107         return fieldOrMethodId;
108     }
109 
getUnused2()110     public int getUnused2() {
111         return unused2;
112     }
113 
writeTo(Section out)114     public void writeTo(Section out) {
115         out.writeUnsignedShort(methodHandleType.value);
116         out.writeUnsignedShort(unused1);
117         out.writeUnsignedShort(fieldOrMethodId);
118         out.writeUnsignedShort(unused2);
119     }
120 
121     @Override
toString()122     public String toString() {
123         if (dex == null) {
124             return methodHandleType + " " + fieldOrMethodId;
125         }
126         return methodHandleType
127                 + " "
128                 + (methodHandleType.isField()
129                         ? dex.fieldIds().get(fieldOrMethodId)
130                         : dex.methodIds().get(fieldOrMethodId));
131     }
132 }
133