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