/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.classloader;
import java.io.DataInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import org.jikesrvm.VM;
import org.vmmagic.pragma.Uninterruptible;
/**
* A common abstract super class for all elements that can be
* annotated within the JVM. Namely classes, methods and fields.
*/
public abstract class VM_AnnotatedElement implements AnnotatedElement {
/**
* Annotations from the class file that are described as runtime
* visible. These annotations are available to the reflection API.
*/
protected final VM_Annotation[] declaredAnnotationDatas;
/** Cached array of declared annotations. */
private Annotation[] declaredAnnotations;
/**
* Constructor used by all annotated elements
*
* @param annotations array of runtime visible annotations
*/
protected VM_AnnotatedElement(VM_Annotation[] annotations) {
this.declaredAnnotationDatas = annotations;
}
/**
* Read annotations from a class file and package in an array
* @param constantPool the constantPool of the VM_Class object
* that's being constructed
* @param input the DataInputStream to read the method's attributes
* from
* @param numAnnotationBytes how many bytes are there in the number
* of annotations field? Normally 2, but parameter annotations just
* have 1.
* @return an array of read annotations
*/
protected static VM_Annotation[] readAnnotations(int[] constantPool, DataInputStream input, int numAnnotationBytes,
ClassLoader classLoader) throws IOException {
try {
int numAnnotations;
if (numAnnotationBytes == 2) {
numAnnotations = input.readUnsignedShort();
} else {
if (VM.VerifyAssertions) VM._assert(numAnnotationBytes == 1);
numAnnotations = input.readByte() & 0xFF;
}
final VM_Annotation[] annotations = new VM_Annotation[numAnnotations];
for (int j = 0; j < numAnnotations; j++) {
annotations[j] = VM_Annotation.readAnnotation(constantPool, input, classLoader);
}
return annotations;
} catch (ClassNotFoundException e) {
throw new Error(e);
}
}
/**
* Get the annotations for this and all super annotated elements.
*/
public final Annotation[] getAnnotations() {
return cloneAnnotations(getAnnotationsInternal());
}
Annotation[] getAnnotationsInternal() {
return getDeclaredAnnotationsInternal();
}
/**
* Get the annotations for this annotated element
*/
public final Annotation[] getDeclaredAnnotations() {
return cloneAnnotations(getDeclaredAnnotationsInternal());
}
final Annotation[] getDeclaredAnnotationsInternal() {
if (null == declaredAnnotations) {
declaredAnnotations = toAnnotations(declaredAnnotationDatas);
}
return declaredAnnotations;
}
/**
* Copy array of annotations so can be safely returned to user.
*/
private Annotation[] cloneAnnotations(final Annotation[] internal) {
final Annotation[] annotations = new Annotation[internal.length];
System.arraycopy(internal, 0, annotations, 0, internal.length);
return annotations;
}
protected static short createAnnoModifer(VM_Annotation[] annotations) {
short annoModifiers = 0;
if (annotations != null) {
for (VM_Annotation annotation : annotations) {
if (annotation.getType().equals(VM_ClassLoaderConstants.RUN_ON_SUBARCH)) {
annoModifiers |= VM_ClassLoaderConstants.ANO_SUBARCH;
} else if (annotation.getType().equals(VM_ClassLoaderConstants.NO_MAIN_ARCH_COMPILE)) {
annoModifiers |= VM_ClassLoaderConstants.ANO_NO_MAINARCH;
} else if (annotation.getType().equals(VM_ClassLoaderConstants.NO_SUB_ARCH_COMPILE)) {
annoModifiers |= VM_ClassLoaderConstants.ANO_NO_SUBARCH;
} else if (annotation.getType().equals(VM_ClassLoaderConstants.ENTRYPOINT_METHOD)) {
annoModifiers |= VM_ClassLoaderConstants.ANO_ENTRYPOINT;
}
}
}
return annoModifiers;
}
/**
* Convert annotations from internal format to annotation instances.
*
* @param annotations the annotations.
* @return the annotation instances.
*/
final Annotation[] toAnnotations(final VM_Annotation[] annotations) {
if (null == annotations) {
return new Annotation[0];
} else {
final Annotation[] copy = new Annotation[annotations.length];
for (int i = 0; i < copy.length; i++) {
copy[i] = annotations[i].getValue();
}
return copy;
}
}
/**
* Get the annotation implementing the specified class or null
*/
@SuppressWarnings({"unchecked"})
public final <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
if (null == annotationClass) {
throw new NullPointerException("annotationClass");
}
final Annotation[] annotations = getAnnotationsInternal();
for (final Annotation annotation : annotations) {
if (annotationClass.isInstance(annotation)) return (T) annotation;
}
return null;
}
/**
* Is there an annotation of this type implemented on this annotated
* element?
*/
public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return getAnnotation(annotationClass) != null;
}
/**
* Return true if annotation present.
*
* This is provided as an alternative to isAnnotationPresent() as isAnnotationPresent()
* may require classloading and instantiation of annotations. Classloading would mean
* that it would not be @Uninterruptible. Instantiation is not desirtable as checking
* of annotations occurs prior to the bootimage compiler being ready to instantiate
* objects.
*/
@Uninterruptible
final boolean isAnnotationDeclared(final VM_TypeReference annotationTypeRef) {
if (null != declaredAnnotationDatas) {
for (VM_Annotation annotation : declaredAnnotationDatas) {
if (annotation.getType().equals(annotationTypeRef.getName()) &&
annotation.getClassLoader() == annotationTypeRef.getClassLoader()) {
return true;
}
}
}
return false;
}
/**
* Return true if this element has a Interruptible annotation.
* @see org.vmmagic.pragma.Interruptible
*/
public final boolean hasInterruptibleAnnotation() {
return isAnnotationDeclared(VM_TypeReference.Interruptible);
}
/**
* Return true if this element has a LogicallyUninterruptible annotation.
* @see org.vmmagic.pragma.LogicallyUninterruptible
*/
public final boolean hasLogicallyUninterruptibleAnnotation() {
return isAnnotationDeclared(VM_TypeReference.LogicallyUninterruptible);
}
/**
* Return true if this element has a NoOptCompile annotation.
* @see org.vmmagic.pragma.NoOptCompile
*/
public final boolean hasNoOptCompileAnnotation() {
return isAnnotationDeclared(VM_TypeReference.NoOptCompile);
}
/**
* Return true if this element has a Preemptible annotation.
* @see org.vmmagic.pragma.Preemptible
*/
public final boolean hasPreemptibleAnnotation() {
return isAnnotationDeclared(VM_TypeReference.Preemptible);
}
/**
* Return true if this element has a UninterruptibleNoWarn annotation.
* @see org.vmmagic.pragma.UninterruptibleNoWarn
*/
public final boolean hasUninterruptibleNoWarnAnnotation() {
return isAnnotationDeclared(VM_TypeReference.UninterruptibleNoWarn);
}
/**
* Return true if this element has a Uninterruptible annotation.
* @see org.vmmagic.pragma.Uninterruptible
*/
public final boolean hasUninterruptibleAnnotation() {
return isAnnotationDeclared(VM_TypeReference.Uninterruptible);
}
/**
* Return true if this element has a Unpreemptible annotation.
* @see org.vmmagic.pragma.Unpreemptible
*/
public final boolean hasUnpreemptibleAnnotation() {
return isAnnotationDeclared(VM_TypeReference.Unpreemptible);
}
/**
* Return true if this element has a Inline annotation.
* @see org.vmmagic.pragma.Inline
*/
public final boolean hasInlineAnnotation() {
return isAnnotationDeclared(VM_TypeReference.Inline);
}
/**
* Return true if this element has a NoInline annotation.
* @see org.vmmagic.pragma.NoInline
*/
public final boolean hasNoInlineAnnotation() {
return isAnnotationDeclared(VM_TypeReference.NoInline);
}
/**
* Return true if this element has a BaselineNoRegisters annotation.
* @see org.vmmagic.pragma.BaselineNoRegisters
*/
public final boolean hasBaselineNoRegistersAnnotation() {
return isAnnotationDeclared(VM_TypeReference.BaselineNoRegisters);
}
/**
* Return true if this element has a BaselineSaveLSRegisters annotation.
* @see org.vmmagic.pragma.BaselineSaveLSRegisters
*/
public final boolean hasBaselineSaveLSRegistersAnnotation() {
return isAnnotationDeclared(VM_TypeReference.BaselineSaveLSRegisters);
}
/**
* Return true if this element has a Pure annotation.
* @see org.vmmagic.pragma.Pure
*/
public final boolean hasPureAnnotation() {
return isAnnotationDeclared(VM_TypeReference.Pure);
}
/**
* Return true if this element has a NoNullCheck annotation.
* @see org.vmmagic.pragma.NoNullCheck
*/
public final boolean hasNoNullCheckAnnotation() {
return isAnnotationDeclared(VM_TypeReference.NoNullCheck);
}
/**
* Return true if this element has a NoBoundsCheck annotation.
* @see org.vmmagic.pragma.NoBoundsCheck
*/
public final boolean hasNoBoundsCheckAnnotation() {
return isAnnotationDeclared(VM_TypeReference.NoBoundsCheck);
}
/**
* Return true if this element has a RuntimeFinal annotation.
* @see org.vmmagic.pragma.RuntimeFinal
*/
public final boolean hasRuntimeFinalAnnotation() {
return isAnnotationDeclared(VM_TypeReference.RuntimeFinal);
}
}