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 */ 16package com.android.dx.dex.file; 17 18import com.android.dx.rop.cst.Constant; 19import com.android.dx.rop.cst.CstBaseMethodRef; 20import com.android.dx.rop.cst.CstFieldRef; 21import com.android.dx.rop.cst.CstInterfaceMethodRef; 22import com.android.dx.rop.cst.CstMethodHandle; 23import com.android.dx.util.AnnotatedOutput; 24import com.android.dx.util.Hex; 25 26/** 27 * Representation of a method handle in a DEX file. 28 */ 29public final class MethodHandleItem extends IndexedItem { 30 31 /** The item size when placed in a DEX file. */ 32 private final int ITEM_SIZE = 8; 33 34 /** {@code non-null;} The method handle represented by this item. */ 35 private final CstMethodHandle methodHandle; 36 37 /** 38 * Constructs an instance. 39 * 40 * @param methodHandle {@code non-null;} The method handle to represent in the DEX file. 41 */ 42 public MethodHandleItem(CstMethodHandle methodHandle) { 43 this.methodHandle = methodHandle; 44 } 45 46 /** {@inheritDoc} */ 47 @Override 48 public ItemType itemType() { 49 return ItemType.TYPE_METHOD_HANDLE_ITEM; 50 } 51 52 /** {@inheritDoc} */ 53 @Override 54 public int writeSize() { 55 return ITEM_SIZE; 56 } 57 58 /** {@inheritDoc} */ 59 @Override 60 public void addContents(DexFile file) { 61 MethodHandlesSection methodHandles = file.getMethodHandles(); 62 methodHandles.intern(methodHandle); 63 } 64 65 /** {@inheritDoc} */ 66 @Override 67 public void writeTo(DexFile file, AnnotatedOutput out) { 68 int targetIndex = getTargetIndex(file); 69 int mhType = methodHandle.getMethodHandleType(); 70 if (out.annotates()) { 71 out.annotate(0, indexString() + ' ' + methodHandle.toString()); 72 String typeComment = " // " + CstMethodHandle.getMethodHandleTypeName(mhType); 73 out.annotate(2, "type: " + Hex.u2(mhType) + typeComment); 74 out.annotate(2, "reserved: " + Hex.u2(0)); 75 String targetComment = " // " + methodHandle.getRef().toString(); 76 if (methodHandle.isAccessor()) { 77 out.annotate(2, "fieldId: " + Hex.u2(targetIndex) + targetComment); 78 } else { 79 out.annotate(2, "methodId: " + Hex.u2(targetIndex) + targetComment); 80 } 81 out.annotate(2, "reserved: " + Hex.u2(0)); 82 } 83 out.writeShort(mhType); 84 out.writeShort(0); 85 out.writeShort(getTargetIndex(file)); 86 out.writeShort(0); 87 } 88 89 private int getTargetIndex(DexFile file) { 90 Constant ref = methodHandle.getRef(); 91 if (methodHandle.isAccessor()) { 92 FieldIdsSection fieldIds = file.getFieldIds(); 93 return fieldIds.indexOf((CstFieldRef) ref); 94 } else if (methodHandle.isInvocation()) { 95 if (ref instanceof CstInterfaceMethodRef) { 96 ref = ((CstInterfaceMethodRef)ref).toMethodRef(); 97 } 98 MethodIdsSection methodIds = file.getMethodIds(); 99 return methodIds.indexOf((CstBaseMethodRef) ref); 100 } else { 101 throw new IllegalStateException("Unhandled invocation type"); 102 } 103 } 104} 105