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