1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17/*
18 * Copyright (C) 2012 The Android Open Source Project
19 *
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
23 *
24 *      http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
31 */
32
33package java.lang.reflect;
34
35import com.android.dex.Dex;
36import java.lang.annotation.Annotation;
37import libcore.reflect.AnnotationAccess;
38import libcore.util.EmptyArray;
39
40/**
41 * This class represents methods and constructors.
42 * @hide
43 */
44public final class ArtMethod {
45
46    /** Method's declaring class */
47    private Class<?> declaringClass;
48    /** Method access flags (modifiers) */
49    private int accessFlags;
50    /** DexFile index */
51    private int methodDexIndex;
52    /** Dispatch table entry */
53    private int methodIndex;
54    /** DexFile offset of CodeItem for this Method */
55    private int codeItemOffset;
56    /* ART compiler meta-data */
57    private int frameSizeInBytes;
58    private int coreSpillMask;
59    private int fpSpillMask;
60    private int mappingTable;
61    private int gcMap;
62    private int vmapTable;
63    /** ART: compiled managed code associated with this Method */
64    private int entryPointFromCompiledCode;
65    /** ART: entry point from interpreter associated with this Method */
66    private int entryPointFromInterpreter;
67    /** ART: if this is a native method, the native code that will be invoked */
68    private int nativeMethod;
69    /* ART: dex cache fast access */
70    private String[] dexCacheStrings;
71    Class<?>[] dexCacheResolvedTypes;
72    private ArtMethod[] dexCacheResolvedMethods;
73    private Object[] dexCacheInitializedStaticStorage;
74
75    /**
76     * Only created by art directly.
77     */
78    private ArtMethod() {}
79
80    Class getDeclaringClass() {
81        return declaringClass;
82    }
83
84    public int getAccessFlags() {
85        return accessFlags;
86    }
87
88    int getDexMethodIndex() {
89        return methodDexIndex;
90    }
91
92    public static String getMethodName(ArtMethod artMethod) {
93        artMethod = artMethod.findOverriddenMethodIfProxy();
94        Dex dex = artMethod.getDeclaringClass().getDex();
95        int nameIndex = dex.nameIndexFromMethodIndex(artMethod.getDexMethodIndex());
96        // Note, in the case of a Proxy the dex cache strings are equal.
97        return artMethod.getDexCacheString(dex, nameIndex);
98    }
99
100    /**
101     * Returns true if the given parameters match those of the method in the given order.
102     *
103     * @hide
104     */
105    public static boolean equalConstructorParameters(ArtMethod artMethod, Class<?>[] params) {
106        Dex dex = artMethod.getDeclaringClass().getDex();
107        short[] types = dex.parameterTypeIndicesFromMethodIndex(artMethod.getDexMethodIndex());
108        if (types.length != params.length) {
109            return false;
110        }
111        for (int i = 0; i < types.length; i++) {
112            if (artMethod.getDexCacheType(dex, types[i]) != params[i]) {
113                return false;
114            }
115        }
116        return true;
117    }
118
119    /**
120     * Returns true if the given parameters match those of this method in the given order.
121     *
122     * @hide
123     */
124    public static boolean equalMethodParameters(ArtMethod artMethod, Class<?>[] params) {
125        return equalConstructorParameters(artMethod.findOverriddenMethodIfProxy(), params);
126    }
127
128    Class<?>[] getParameterTypes() {
129        Dex dex = getDeclaringClass().getDex();
130        short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex);
131        if (types.length == 0) {
132            return EmptyArray.CLASS;
133        }
134        Class<?>[] parametersArray = new Class[types.length];
135        for (int i = 0; i < types.length; i++) {
136            // Note, in the case of a Proxy the dex cache types are equal.
137            parametersArray[i] = getDexCacheType(dex, types[i]);
138        }
139        return parametersArray;
140    }
141
142    Class<?> getReturnType() {
143        Dex dex = declaringClass.getDex();
144        int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(methodDexIndex);
145        // Note, in the case of a Proxy the dex cache types are equal.
146        return getDexCacheType(dex, returnTypeIndex);
147    }
148
149    /**
150     * Performs a comparison of the parameters to this method with the given parameters.
151     *
152     * @hide
153     */
154    int compareParameters(Class<?>[] params) {
155        Dex dex = getDeclaringClass().getDex();
156        short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex);
157        int length = Math.min(types.length, params.length);
158        for (int i = 0; i < length; i++) {
159            Class<?> aType = getDexCacheType(dex, types[i]);
160            Class<?> bType = params[i];
161            if (aType != bType) {
162                int comparison = aType.getName().compareTo(bType.getName());
163                if (comparison != 0) {
164                    return comparison;
165                }
166            }
167        }
168        return types.length - params.length;
169    }
170
171    Annotation[][] getParameterAnnotations() {
172        return AnnotationAccess.getParameterAnnotations(declaringClass, methodDexIndex);
173    }
174
175    /**
176     * Returns a string from the dex cache, computing the string from the dex file if necessary.
177     * Note this method replicates {@link java.lang.Class#getDexCacheString(Dex, int)}, but in
178     * Method we can avoid one indirection.
179     */
180    private String getDexCacheString(Dex dex, int dexStringIndex) {
181        String s = (String) dexCacheStrings[dexStringIndex];
182        if (s == null) {
183            s = dex.strings().get(dexStringIndex).intern();
184            dexCacheStrings[dexStringIndex] = s;
185        }
186        return s;
187    }
188
189    /**
190     * Returns a resolved type from the dex cache, computing the string from the dex file if
191     * necessary. Note this method delegates to {@link java.lang.Class#getDexCacheType(Dex, int)},
192     * but in Method we can avoid one indirection.
193     */
194    private Class<?> getDexCacheType(Dex dex, int dexTypeIndex) {
195        Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex];
196        if (resolvedType == null) {
197            resolvedType = declaringClass.getDexCacheType(dex, dexTypeIndex);
198        }
199        return resolvedType;
200    }
201
202    /**
203     * Returns the {@code ArtMethod} that this method overrides for
204     * proxy methods, otherwise returns this method. Used to determine
205     * the interface method overridden by a proxy method (as the proxy
206     * method doesn't directly support operations such as {@link
207     * Method#getName}).
208     */
209    ArtMethod findOverriddenMethodIfProxy() {
210        if (declaringClass.isProxy()) {
211            // Proxy method's declaring class' dex cache refers to that of Proxy. The local cache in
212            // Method refers to the original interface's dex cache and is ensured to be resolved by
213            // proxy generation.
214            return dexCacheResolvedMethods[methodDexIndex];
215        }
216        return this;
217    }
218}
219