blob: 5e56d8712a0d328b3d6073292ec106e7d4846fbe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/*
* Copyright (C) 2012 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 java.lang.reflect;
import com.android.dex.Dex;
import java.lang.annotation.Annotation;
import libcore.reflect.AnnotationAccess;
import libcore.reflect.InternalNames;
import libcore.util.EmptyArray;
/**
* This class represents methods and constructors.
* @hide
*/
public final class ArtMethod {
/** Method's declaring class */
private Class<?> declaringClass;
/** Method access flags (modifiers) */
private int accessFlags;
/** DexFile index */
private int methodDexIndex;
/** Dispatch table entry */
private int methodIndex;
/** DexFile offset of CodeItem for this Method */
private int codeItemOffset;
/* ART compiler meta-data */
private int frameSizeInBytes;
private int coreSpillMask;
private int fpSpillMask;
private int mappingTable;
private int gcMap;
private int vmapTable;
/** ART: compiled managed code associated with this Method */
private int entryPointFromCompiledCode;
/** ART: entry point from interpreter associated with this Method */
private int entryPointFromInterpreter;
/** ART: if this is a native method, the native code that will be invoked */
private int nativeMethod;
/* ART: dex cache fast access */
private String[] dexCacheStrings;
Class<?>[] dexCacheResolvedTypes;
private ArtMethod[] dexCacheResolvedMethods;
private Object[] dexCacheInitializedStaticStorage;
/**
* Only created by art directly.
*/
private ArtMethod() {}
Class getDeclaringClass() {
return declaringClass;
}
public int getAccessFlags() {
return accessFlags;
}
int getDexMethodIndex() {
return methodDexIndex;
}
public static String getMethodName(ArtMethod artMethod) {
artMethod = artMethod.findOverriddenMethodIfProxy();
Dex dex = artMethod.getDeclaringClass().getDex();
int nameIndex = dex.nameIndexFromMethodIndex(artMethod.getDexMethodIndex());
// Note, in the case of a Proxy the dex cache strings are equal.
return artMethod.getDexCacheString(dex, nameIndex);
}
/**
* Returns true if the given parameters match those of the method in the given order.
*
* @hide
*/
public static boolean equalConstructorParameters(ArtMethod artMethod, Class<?>[] params) {
Dex dex = artMethod.getDeclaringClass().getDex();
short[] types = dex.parameterTypeIndicesFromMethodIndex(artMethod.getDexMethodIndex());
if (types.length != params.length) {
return false;
}
for (int i = 0; i < types.length; i++) {
if (artMethod.getDexCacheType(dex, types[i]) != params[i]) {
return false;
}
}
return true;
}
/**
* Returns true if the given parameters match those of this method in the given order.
*
* @hide
*/
public static boolean equalMethodParameters(ArtMethod artMethod, Class<?>[] params) {
return equalConstructorParameters(artMethod.findOverriddenMethodIfProxy(), params);
}
Class<?>[] getParameterTypes() {
Dex dex = getDeclaringClass().getDex();
short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex);
if (types.length == 0) {
return EmptyArray.CLASS;
}
Class<?>[] parametersArray = new Class[types.length];
for (int i = 0; i < types.length; i++) {
// Note, in the case of a Proxy the dex cache types are equal.
parametersArray[i] = getDexCacheType(dex, types[i]);
}
return parametersArray;
}
Class<?> getReturnType() {
Dex dex = declaringClass.getDex();
int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(methodDexIndex);
// Note, in the case of a Proxy the dex cache types are equal.
return getDexCacheType(dex, returnTypeIndex);
}
/**
* Performs a comparison of the parameters to this method with the given parameters.
*
* @hide
*/
int compareParameters(Class<?>[] params) {
Dex dex = getDeclaringClass().getDex();
short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex);
int length = Math.min(types.length, params.length);
for (int i = 0; i < length; i++) {
Class<?> aType = getDexCacheType(dex, types[i]);
Class<?> bType = params[i];
if (aType != bType) {
int comparison = aType.getName().compareTo(bType.getName());
if (comparison != 0) {
return comparison;
}
}
}
return types.length - params.length;
}
Annotation[][] getParameterAnnotations() {
return AnnotationAccess.getParameterAnnotations(declaringClass, methodDexIndex);
}
/**
* Returns a string from the dex cache, computing the string from the dex file if necessary.
* Note this method replicates {@link java.lang.Class#getDexCacheString(Dex, int)}, but in
* Method we can avoid one indirection.
*/
private String getDexCacheString(Dex dex, int dexStringIndex) {
String s = (String) dexCacheStrings[dexStringIndex];
if (s == null) {
s = dex.strings().get(dexStringIndex);
dexCacheStrings[dexStringIndex] = s;
}
return s;
}
/**
* Returns a resolved type from the dex cache, computing the string from the dex file if
* necessary. Note this method replicates {@link java.lang.Class#getDexCacheType(Dex, int)},
* but in Method we can avoid one indirection.
*/
private Class<?> getDexCacheType(Dex dex, int dexTypeIndex) {
Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex];
if (resolvedType == null) {
int descriptorIndex = dex.typeIds().get(dexTypeIndex);
String descriptor = getDexCacheString(dex, descriptorIndex);
resolvedType = InternalNames.getClass(declaringClass.getClassLoader(),
descriptor);
dexCacheResolvedTypes[dexTypeIndex] = resolvedType;
}
return resolvedType;
}
/**
* Returns the {@code ArtMethod} that this method overrides for
* proxy methods, otherwise returns this method. Used to determine
* the interface method overridden by a proxy method (as the proxy
* method doesn't directly support operations such as {@link
* Method#getName}).
*/
ArtMethod findOverriddenMethodIfProxy() {
if (declaringClass.isProxy()) {
// Proxy method's declaring class' dex cache refers to that of Proxy. The local cache in
// Method refers to the original interface's dex cache and is ensured to be resolved by
// proxy generation.
return dexCacheResolvedMethods[methodDexIndex];
}
return this;
}
}