1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file 2 // for details. All rights reserved. Use of this source code is governed by a 3 // BSD-style license that can be found in the LICENSE file. 4 package com.android.tools.r8.graph; 5 6 import com.android.tools.r8.dex.IndexedItemCollection; 7 8 public class DexMethodHandle extends IndexedDexItem { 9 10 public enum MethodHandleType { 11 // Method handle dex type. 12 STATIC_PUT((short) 0x00), 13 STATIC_GET((short) 0x01), 14 INSTANCE_PUT((short) 0x02), 15 INSTANCE_GET((short) 0x03), 16 INVOKE_STATIC((short) 0x04), 17 INVOKE_INSTANCE((short) 0x05), 18 // Upcoming method handle dex type. 19 INVOKE_CONSTRUCTOR((short) 0x06), 20 // Internal method handle needed by lambda desugaring. 21 INVOKE_INTERFACE((short) 0x07), 22 INVOKE_SUPER((short) 0x08); 23 24 private final short value; 25 MethodHandleType(short value)26 MethodHandleType(short value) { 27 this.value = value; 28 } 29 getValue()30 public short getValue() { 31 return value; 32 } 33 getKind(int value)34 public static MethodHandleType getKind(int value) { 35 MethodHandleType kind; 36 37 switch (value) { 38 case 0x00: 39 kind = STATIC_PUT; 40 break; 41 case 0x01: 42 kind = STATIC_GET; 43 break; 44 case 0x02: 45 kind = INSTANCE_PUT; 46 break; 47 case 0x03: 48 kind = INSTANCE_GET; 49 break; 50 case 0x04: 51 kind = INVOKE_STATIC; 52 break; 53 case 0x05: 54 kind = INVOKE_INSTANCE; 55 break; 56 case 0x06: 57 kind = INVOKE_CONSTRUCTOR; 58 break; 59 case 0x07: 60 kind = INVOKE_INTERFACE; 61 break; 62 case 0x08: 63 kind = INVOKE_SUPER; 64 break; 65 default: 66 throw new AssertionError(); 67 } 68 69 assert kind.getValue() == value; 70 return kind; 71 } 72 isFieldType()73 public boolean isFieldType() { 74 return isStaticPut() || isStaticGet() || isInstancePut() || isInstanceGet(); 75 } 76 isMethodType()77 public boolean isMethodType() { 78 return isInvokeStatic() || isInvokeInstance() || isInvokeInterface() || isInvokeSuper() 79 || isInvokeConstructor(); 80 } 81 isStaticPut()82 public boolean isStaticPut() { 83 return this == MethodHandleType.STATIC_PUT; 84 } 85 isStaticGet()86 public boolean isStaticGet() { 87 return this == MethodHandleType.STATIC_GET; 88 } 89 isInstancePut()90 public boolean isInstancePut() { 91 return this == MethodHandleType.INSTANCE_PUT; 92 } 93 isInstanceGet()94 public boolean isInstanceGet() { 95 return this == MethodHandleType.INSTANCE_GET; 96 } 97 isInvokeStatic()98 public boolean isInvokeStatic() { 99 return this == MethodHandleType.INVOKE_STATIC; 100 } 101 isInvokeInstance()102 public boolean isInvokeInstance() { 103 return this == MethodHandleType.INVOKE_INSTANCE; 104 } 105 isInvokeInterface()106 public boolean isInvokeInterface() { 107 return this == MethodHandleType.INVOKE_INTERFACE; 108 } 109 isInvokeSuper()110 public boolean isInvokeSuper() { 111 return this == MethodHandleType.INVOKE_SUPER; 112 } 113 isInvokeConstructor()114 public boolean isInvokeConstructor() { 115 return this == MethodHandleType.INVOKE_CONSTRUCTOR; 116 } 117 } 118 119 public MethodHandleType type; 120 public Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod; 121 DexMethodHandle( MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod)122 public DexMethodHandle( 123 MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod) { 124 this.type = type; 125 this.fieldOrMethod = fieldOrMethod; 126 } 127 computeHashCode()128 public int computeHashCode() { 129 return type.hashCode() + fieldOrMethod.computeHashCode() * 7; 130 } 131 computeEquals(Object other)132 public boolean computeEquals(Object other) { 133 if (other instanceof DexMethodHandle) { 134 DexMethodHandle o = (DexMethodHandle) other; 135 return type.equals(o.type) && fieldOrMethod.equals(o.fieldOrMethod); 136 } 137 return false; 138 } 139 toString()140 public String toString() { 141 StringBuilder builder = new StringBuilder("MethodHandle: {") 142 .append(type) 143 .append(", ") 144 .append(fieldOrMethod.toSourceString()) 145 .append("}"); 146 return builder.toString(); 147 } 148 149 @Override collectIndexedItems(IndexedItemCollection indexedItems)150 public void collectIndexedItems(IndexedItemCollection indexedItems) { 151 if (indexedItems.addMethodHandle(this)) { 152 fieldOrMethod.collectIndexedItems(indexedItems); 153 } 154 } 155 156 @Override getOffset(ObjectToOffsetMapping mapping)157 public int getOffset(ObjectToOffsetMapping mapping) { 158 return mapping.getOffsetFor(this); 159 } 160 161 // TODO(mikaelpeltier): Adapt syntax when invoke-custom will be available into smali. toSmaliString()162 public String toSmaliString() { 163 return toString(); 164 } 165 isFieldHandle()166 public boolean isFieldHandle() { 167 return type.isFieldType(); 168 } 169 isMethodHandle()170 public boolean isMethodHandle() { 171 return type.isMethodType(); 172 } 173 isStaticHandle()174 public boolean isStaticHandle() { 175 return type.isStaticPut() || type.isStaticGet() || type.isInvokeStatic(); 176 } 177 asMethod()178 public DexMethod asMethod() { 179 assert isMethodHandle(); 180 return (DexMethod) fieldOrMethod; 181 } 182 asField()183 public DexField asField() { 184 assert isFieldHandle(); 185 return (DexField) fieldOrMethod; 186 } 187 } 188