Home | History | Annotate | Download | only in dex
      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 
     45         MethodHandleType(int value) {
     46             this.value = value;
     47         }
     48 
     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 
     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 
     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
     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 
     98     public MethodHandleType getMethodHandleType() {
     99         return methodHandleType;
    100     }
    101 
    102     public int getUnused1() {
    103         return unused1;
    104     }
    105 
    106     public int getFieldOrMethodId() {
    107         return fieldOrMethodId;
    108     }
    109 
    110     public int getUnused2() {
    111         return unused2;
    112     }
    113 
    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
    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