001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.classloader;
014
015import java.io.DataInputStream;
016import java.io.IOException;
017import java.lang.annotation.Annotation;
018
019import org.vmmagic.pragma.Uninterruptible;
020import org.jikesrvm.VM;
021
022/**
023 * A common abstract super class for all elements that can be
024 * annotated within the JVM. Namely classes, methods and fields.
025 */
026public abstract class AnnotatedElement implements java.lang.reflect.AnnotatedElement {
027  /**
028   * Annotations from the class file that are described as runtime
029   * visible. These annotations are available to the reflection API.
030   * This is either null, a RVMAnnotation if a single annotation is
031   * present, or an array of RVMAnnotation if there is >1
032   */
033  protected final Object declaredAnnotationDatas;
034  /** Cached array of declared annotations. */
035  private Annotation[] declaredAnnotations;
036  /** Empty annotation array */
037  private static final Annotation[] emptyAnnotationArray = new Annotation[0];
038
039  /**
040   * Constructor used by all annotated elements
041   *
042   * @param annotations array of runtime visible annotations
043   */
044  protected AnnotatedElement(RVMAnnotation[] annotations) {
045    if (annotations == null) {
046      declaredAnnotationDatas = null;
047      declaredAnnotations = emptyAnnotationArray;
048    } else if (annotations.length == 1) {
049      this.declaredAnnotationDatas = annotations[0];
050    } else {
051      this.declaredAnnotationDatas = annotations;
052    }
053    if (annotations != null) {
054      for (RVMAnnotation ann : annotations) {
055        if (ann == null)  throw new Error("null annotation in " + toString());
056      }
057    }
058  }
059
060  protected static RVMAnnotation[] readAnnotations(int[] constantPool, DataInputStream input,
061                                                   ClassLoader classLoader) throws IOException {
062    try {
063      int numAnnotations = input.readUnsignedShort();
064      final RVMAnnotation[] annotations = new RVMAnnotation[numAnnotations];
065      for (int j = 0; j < numAnnotations; j++) {
066        annotations[j] = RVMAnnotation.readAnnotation(constantPool, input, classLoader);
067      }
068      return annotations;
069    } catch (ClassNotFoundException e) {
070      throw new Error(e);
071    }
072  }
073
074  /**
075   * Get the annotations for this and all super annotated elements.
076   */
077  @Override
078  public final Annotation[] getAnnotations() {
079    return cloneAnnotations(getAnnotationsInternal());
080  }
081
082  Annotation[] getAnnotationsInternal() {
083    return getDeclaredAnnotationsInternal();
084  }
085
086  /**
087   * Get the annotations for this annotated element
088   */
089  @Override
090  public final Annotation[] getDeclaredAnnotations() {
091    return cloneAnnotations(getDeclaredAnnotationsInternal());
092  }
093
094  final Annotation[] getDeclaredAnnotationsInternal() {
095    if (!VM.runningVM) {
096      return toAnnotations(declaredAnnotationDatas);
097    }
098    if (null == declaredAnnotations) {
099      declaredAnnotations = toAnnotations(declaredAnnotationDatas);
100    }
101    return declaredAnnotations;
102  }
103
104  private Annotation[] cloneAnnotations(final Annotation[] internal) {
105    if (internal.length == 0) {
106      return emptyAnnotationArray;
107    } else {
108      final Annotation[] annotations = new Annotation[internal.length];
109      System.arraycopy(internal, 0, annotations, 0, internal.length);
110      return annotations;
111    }
112  }
113
114  /**
115   * Convert annotations from internal format to annotation instances.
116   *
117   * @param datas the annotations.
118   * @return the annotation instances.
119   */
120  final Annotation[] toAnnotations(final Object datas) {
121    if (null == datas) {
122      return emptyAnnotationArray;
123    } else if (datas instanceof RVMAnnotation) {
124      final Annotation[] copy = new Annotation[1];
125      copy[0] = ((RVMAnnotation)datas).getValue();
126      return copy;
127    } else {
128      RVMAnnotation[] annotations = (RVMAnnotation[])datas;
129      final Annotation[] copy = new Annotation[annotations.length];
130      for (int i = 0; i < copy.length; i++) {
131        copy[i] = annotations[i].getValue();
132      }
133      return copy;
134    }
135  }
136
137  /**
138   * Get the annotation implementing the specified class or null
139   */
140  @Override
141  @SuppressWarnings({"unchecked"})
142  public final <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
143    if (null == annotationClass) {
144      throw new NullPointerException("annotationClass");
145    }
146    final Annotation[] annotations = getAnnotationsInternal();
147    for (final Annotation annotation : annotations) {
148      if (annotationClass.isInstance(annotation)) return (T) annotation;
149    }
150    return null;
151  }
152
153  /**
154   * Is there an annotation of this type implemented on this annotated
155   * element?
156   */
157  @Override
158  public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
159    return getAnnotation(annotationClass) != null;
160  }
161
162  /**
163   * Checks if an annotation is declared.
164   * <p>
165   * This is provided as an alternative to isAnnotationPresent() as isAnnotationPresent()
166   * may require classloading and instantiation of annotations. Classloading would mean
167   * that it would not be @Uninterruptible. Instantiation is not desirable as checking
168   * of annotations occurs prior to the bootimage compiler being ready to instantiate
169   * objects.
170   *
171   * @param annotationTypeRef the annotation to check for
172   * @return {@code true} if annotation present.
173   */
174  @Uninterruptible
175  final boolean isAnnotationDeclared(final TypeReference annotationTypeRef) {
176    if (declaredAnnotationDatas == null) {
177      return false;
178    } else if (declaredAnnotationDatas instanceof RVMAnnotation) {
179      RVMAnnotation annotation = (RVMAnnotation)declaredAnnotationDatas;
180      return annotation.annotationType() == annotationTypeRef;
181    } else {
182      for (RVMAnnotation annotation : (RVMAnnotation[])declaredAnnotationDatas) {
183        if (annotation.annotationType() == annotationTypeRef) {
184          return true;
185        }
186      }
187      return false;
188    }
189  }
190
191  /**
192   * @return {@code true} if the element has at least one annotation
193   */
194  @Uninterruptible
195  public final boolean hasAnnotations() {
196    return declaredAnnotationDatas != null;
197  }
198
199  /**
200   * @return {@code true} if this element has a Interruptible annotation.
201   * @see org.vmmagic.pragma.Interruptible
202   */
203  public final boolean hasInterruptibleAnnotation() {
204    return isAnnotationDeclared(TypeReference.Interruptible);
205  }
206
207  /**
208   * @return {@code true} if this element has a LogicallyUninterruptible annotation.
209   * @see org.vmmagic.pragma.LogicallyUninterruptible
210   */
211  public final boolean hasLogicallyUninterruptibleAnnotation() {
212    return isAnnotationDeclared(TypeReference.LogicallyUninterruptible);
213  }
214
215  /**
216   * @return {@code true} if this element has a Preemptible annotation.
217   * @see org.vmmagic.pragma.Preemptible
218   */
219  public final boolean hasPreemptibleAnnotation() {
220    return isAnnotationDeclared(TypeReference.Preemptible);
221  }
222
223  /**
224   * @return {@code true} if this element has a UninterruptibleNoWarn annotation.
225   * @see org.vmmagic.pragma.UninterruptibleNoWarn
226   */
227  public final boolean hasUninterruptibleNoWarnAnnotation() {
228    return isAnnotationDeclared(TypeReference.UninterruptibleNoWarn);
229  }
230
231  /**
232   * @return {@code true} if this element has a UninterruptibleNoWarn annotation.
233   * @see org.vmmagic.pragma.UninterruptibleNoWarn
234   */
235  public final boolean hasUnpreemptibleNoWarnAnnotation() {
236    return isAnnotationDeclared(TypeReference.UnpreemptibleNoWarn);
237  }
238
239  /**
240   * @return {@code true} if this element has a Uninterruptible annotation.
241   * @see org.vmmagic.pragma.Uninterruptible
242   */
243  public final boolean hasUninterruptibleAnnotation() {
244    return isAnnotationDeclared(TypeReference.Uninterruptible);
245  }
246  /**
247   * @return {@code true} if this element has a NoCheckStore annotation.
248   * @see org.vmmagic.pragma.NoCheckStore
249   */
250  public final boolean hasNoCheckStoreAnnotation() {
251    return isAnnotationDeclared(TypeReference.NoCheckStore);
252  }
253
254  /**
255   * @return {@code true} if this element has a Unpreemptible annotation.
256   * @see org.vmmagic.pragma.Unpreemptible
257   */
258  public final boolean hasUnpreemptibleAnnotation() {
259    return isAnnotationDeclared(TypeReference.Unpreemptible);
260  }
261
262  /**
263   * @return {@code true} if this element has a NoOptCompile annotation.
264   * @see org.vmmagic.pragma.NoOptCompile
265   */
266  public final boolean hasNoOptCompileAnnotation() {
267    return isAnnotationPresent(org.vmmagic.pragma.NoOptCompile.class);
268  }
269
270  /**
271   * @return {@code true} if this element has a Inline annotation.
272   * @see org.vmmagic.pragma.Inline
273   */
274  public final boolean hasInlineAnnotation() {
275    return isAnnotationPresent(org.vmmagic.pragma.Inline.class);
276  }
277
278  /**
279   * @return {@code true} if this element has a NoInline annotation.
280   * @see org.vmmagic.pragma.NoInline
281   */
282  public final boolean hasNoInlineAnnotation() {
283    return isAnnotationPresent(org.vmmagic.pragma.NoInline.class);
284  }
285
286  /**
287   * @return {@code true} if this element has a BaselineNoRegisters annotation.
288   * @see org.vmmagic.pragma.BaselineNoRegisters
289   */
290  public final boolean hasBaselineNoRegistersAnnotation() {
291    return isAnnotationDeclared(TypeReference.BaselineNoRegisters);
292  }
293
294  /**
295   * @return {@code true} if this element has a BaselineSaveLSRegisters annotation.
296   * @see org.vmmagic.pragma.BaselineSaveLSRegisters
297   */
298  @Uninterruptible
299  public final boolean hasBaselineSaveLSRegistersAnnotation() {
300    return isAnnotationDeclared(TypeReference.BaselineSaveLSRegisters);
301  }
302
303  /**
304   * @return {@code true} if this element has a Pure annotation.
305   * @see org.vmmagic.pragma.Pure
306   */
307  public final boolean hasPureAnnotation() {
308    return isAnnotationPresent(org.vmmagic.pragma.Pure.class);
309  }
310
311  /**
312   * @return {@code true} if this element has a RuntimePure annotation.
313   * @see org.vmmagic.pragma.RuntimePure
314   */
315  public final boolean hasRuntimePureAnnotation() {
316    return isAnnotationPresent(org.vmmagic.pragma.RuntimePure.class);
317  }
318
319  /**
320   * @return {@code true} if this element has a NoNullCheck annotation.
321   * @see org.vmmagic.pragma.NoNullCheck
322   */
323  public final boolean hasNoNullCheckAnnotation() {
324    return isAnnotationPresent(org.vmmagic.pragma.NoNullCheck.class);
325  }
326
327  /**
328   * @return {@code true} if this element has a NoBoundsCheck annotation.
329   * @see org.vmmagic.pragma.NoBoundsCheck
330   */
331  public final boolean hasNoBoundsCheckAnnotation() {
332    return isAnnotationPresent(org.vmmagic.pragma.NoBoundsCheck.class);
333  }
334
335  /**
336   * @return {@code true} if this element has a RuntimeFinal annotation.
337   * @see org.vmmagic.pragma.RuntimeFinal
338   */
339  public final boolean hasRuntimeFinalAnnotation() {
340    return isAnnotationPresent(org.vmmagic.pragma.RuntimeFinal.class);
341  }
342
343  /**
344   * @return {@code true} if this element has a NoEscapes annotation.
345   * @see org.vmmagic.pragma.NoEscapes
346   */
347  public final boolean hasNoEscapesAnnotation() {
348    return isAnnotationPresent(org.vmmagic.pragma.NoEscapes.class);
349  }
350
351  /**
352   * @return {@code true} if this element has a Untraced annotation.
353   * @see org.vmmagic.pragma.Untraced
354   */
355  @Uninterruptible
356  public final boolean hasUntracedAnnotation() {
357    return isAnnotationDeclared(TypeReference.Untraced);
358  }
359
360  /**
361   * @return {@code true} if this element has a NonMoving annotation.
362   * @see org.vmmagic.pragma.NonMoving
363   */
364  public final boolean hasNonMovingAnnotation() {
365    return isAnnotationDeclared(TypeReference.NonMoving);
366  }
367
368  /**
369   * @return {@code true} if this element has a NonMovingAllocation annotation.
370   * @see org.vmmagic.pragma.NonMovingAllocation
371   */
372  public final boolean hasNonMovingAllocationAnnotation() {
373    return isAnnotationDeclared(TypeReference.NonMovingAllocation);
374  }
375}