| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.dx.dex.file; |
| |
| import com.android.dx.rop.cst.Constant; |
| import com.android.dx.rop.cst.CstBaseMethodRef; |
| import com.android.dx.rop.cst.CstFieldRef; |
| import com.android.dx.rop.cst.CstInterfaceMethodRef; |
| import com.android.dx.rop.cst.CstMethodHandle; |
| import com.android.dx.util.AnnotatedOutput; |
| import com.android.dx.util.Hex; |
| |
| /** |
| * Representation of a method handle in a DEX file. |
| */ |
| public final class MethodHandleItem extends IndexedItem { |
| |
| /** The item size when placed in a DEX file. */ |
| private final int ITEM_SIZE = 8; |
| |
| /** {@code non-null;} The method handle represented by this item. */ |
| private final CstMethodHandle methodHandle; |
| |
| /** |
| * Constructs an instance. |
| * |
| * @param methodHandle {@code non-null;} The method handle to represent in the DEX file. |
| */ |
| public MethodHandleItem(CstMethodHandle methodHandle) { |
| this.methodHandle = methodHandle; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public ItemType itemType() { |
| return ItemType.TYPE_METHOD_HANDLE_ITEM; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public int writeSize() { |
| return ITEM_SIZE; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void addContents(DexFile file) { |
| MethodHandlesSection methodHandles = file.getMethodHandles(); |
| methodHandles.intern(methodHandle); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void writeTo(DexFile file, AnnotatedOutput out) { |
| int targetIndex = getTargetIndex(file); |
| if (out.annotates()) { |
| out.annotate(2, "kind: " + Hex.u2(methodHandle.getType())); |
| out.annotate(2, "reserved:" + Hex.u2(0)); |
| if (methodHandle.isAccessor()) { |
| out.annotate(2, "fieldId: " + targetIndex); |
| } else { |
| out.annotate(2, "methodId: " + targetIndex); |
| } |
| out.annotate(2, "reserved:" + Hex.u2(0)); |
| } |
| out.writeShort(methodHandle.getType()); |
| out.writeShort(0); |
| out.writeShort(getTargetIndex(file)); |
| out.writeShort(0); |
| } |
| |
| private int getTargetIndex(DexFile file) { |
| Constant ref = methodHandle.getRef(); |
| if (methodHandle.isAccessor()) { |
| FieldIdsSection fieldIds = file.getFieldIds(); |
| return fieldIds.indexOf((CstFieldRef) ref); |
| } else if (methodHandle.isInvocation()) { |
| if (ref instanceof CstInterfaceMethodRef) { |
| ref = ((CstInterfaceMethodRef)ref).toMethodRef(); |
| } |
| MethodIdsSection methodIds = file.getMethodIds(); |
| return methodIds.indexOf((CstBaseMethodRef) ref); |
| } else { |
| throw new IllegalStateException("Unhandled invocation type"); |
| } |
| } |
| } |