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     */
013    package org.jikesrvm.classloader;
014    
015    import java.io.DataInputStream;
016    import java.io.IOException;
017    import java.lang.annotation.Annotation;
018    
019    import org.vmmagic.pragma.Uninterruptible;
020    import 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     */
026    public 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      /**
061       * Read annotations from a class file and package in an array
062       * @param constantPool the constantPool of the RVMClass object
063       * that's being constructed
064       * @param input the DataInputStream to read the method's attributes
065       * from
066       * @return an array of read annotations
067       */
068      protected static RVMAnnotation[] readAnnotations(int[] constantPool, DataInputStream input,
069                                                       ClassLoader classLoader) throws IOException {
070        try {
071          int numAnnotations = input.readUnsignedShort();
072          final RVMAnnotation[] annotations = new RVMAnnotation[numAnnotations];
073          for (int j = 0; j < numAnnotations; j++) {
074            annotations[j] = RVMAnnotation.readAnnotation(constantPool, input, classLoader);
075          }
076          return annotations;
077        } catch (ClassNotFoundException e) {
078          throw new Error(e);
079        }
080      }
081    
082      /**
083       * Get the annotations for this and all super annotated elements.
084       */
085      public final Annotation[] getAnnotations() {
086        return cloneAnnotations(getAnnotationsInternal());
087      }
088    
089      Annotation[] getAnnotationsInternal() {
090        return getDeclaredAnnotationsInternal();
091      }
092    
093      /**
094       * Get the annotations for this annotated element
095       */
096      public final Annotation[] getDeclaredAnnotations() {
097        return cloneAnnotations(getDeclaredAnnotationsInternal());
098      }
099    
100      final Annotation[] getDeclaredAnnotationsInternal() {
101        if (!VM.runningVM) {
102          return toAnnotations(declaredAnnotationDatas);
103        }
104        if (null == declaredAnnotations) {
105          declaredAnnotations = toAnnotations(declaredAnnotationDatas);
106        }
107        return declaredAnnotations;
108      }
109    
110      /**
111       * Copy array of annotations so can be safely returned to user.
112       */
113      private Annotation[] cloneAnnotations(final Annotation[] internal) {
114        if (internal.length == 0) {
115          return emptyAnnotationArray;
116        } else {
117          final Annotation[] annotations = new Annotation[internal.length];
118          System.arraycopy(internal, 0, annotations, 0, internal.length);
119          return annotations;
120        }
121      }
122    
123      /**
124       * Convert annotations from internal format to annotation instances.
125       *
126       * @param datas the annotations.
127       * @return the annotation instances.
128       */
129      final Annotation[] toAnnotations(final Object datas) {
130        if (null == datas) {
131          return emptyAnnotationArray;
132        } else if (datas instanceof RVMAnnotation) {
133          final Annotation[] copy = new Annotation[1];
134          copy[0] = ((RVMAnnotation)datas).getValue();
135          return copy;
136        } else {
137          RVMAnnotation[] annotations = (RVMAnnotation[])datas;
138          final Annotation[] copy = new Annotation[annotations.length];
139          for (int i = 0; i < copy.length; i++) {
140            copy[i] = annotations[i].getValue();
141          }
142          return copy;
143        }
144      }
145    
146      /**
147       * Get the annotation implementing the specified class or null
148       */
149      @SuppressWarnings({"unchecked"})
150      public final <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
151        if (null == annotationClass) {
152          throw new NullPointerException("annotationClass");
153        }
154        final Annotation[] annotations = getAnnotationsInternal();
155        for (final Annotation annotation : annotations) {
156          if (annotationClass.isInstance(annotation)) return (T) annotation;
157        }
158        return null;
159      }
160    
161      /**
162       * Is there an annotation of this type implemented on this annotated
163       * element?
164       */
165      public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
166        return getAnnotation(annotationClass) != null;
167      }
168    
169      /**
170       * Return true if annotation present.
171       *
172       * This is provided as an alternative to isAnnotationPresent() as isAnnotationPresent()
173       * may require classloading and instantiation of annotations. Classloading would mean
174       * that it would not be @Uninterruptible. Instantiation is not desirable as checking
175       * of annotations occurs prior to the bootimage compiler being ready to instantiate
176       * objects.
177       */
178      @Uninterruptible
179      final boolean isAnnotationDeclared(final TypeReference annotationTypeRef) {
180        if (declaredAnnotationDatas == null) {
181          return false;
182        } else if (declaredAnnotationDatas instanceof RVMAnnotation) {
183          RVMAnnotation annotation = (RVMAnnotation)declaredAnnotationDatas;
184          return annotation.annotationType() == annotationTypeRef;
185        } else {
186          for (RVMAnnotation annotation : (RVMAnnotation[])declaredAnnotationDatas) {
187            if (annotation.annotationType() == annotationTypeRef) {
188              return true;
189            }
190          }
191          return false;
192        }
193      }
194    
195      /**
196       * Does the element have any annotations?
197       */
198      @Uninterruptible
199      public final boolean hasAnnotations() {
200        return declaredAnnotationDatas != null;
201      }
202    
203      /**
204       * Return true if this element has a Interruptible annotation.
205       * @see org.vmmagic.pragma.Interruptible
206       */
207      public final boolean hasInterruptibleAnnotation() {
208        return isAnnotationDeclared(TypeReference.Interruptible);
209      }
210    
211      /**
212       * Return true if this element has a LogicallyUninterruptible annotation.
213       * @see org.vmmagic.pragma.LogicallyUninterruptible
214       */
215      public final boolean hasLogicallyUninterruptibleAnnotation() {
216        return isAnnotationDeclared(TypeReference.LogicallyUninterruptible);
217      }
218    
219      /**
220       * Return true if this element has a Preemptible annotation.
221       * @see org.vmmagic.pragma.Preemptible
222       */
223      public final boolean hasPreemptibleAnnotation() {
224        return isAnnotationDeclared(TypeReference.Preemptible);
225      }
226    
227      /**
228       * Return true if this element has a UninterruptibleNoWarn annotation.
229       * @see org.vmmagic.pragma.UninterruptibleNoWarn
230       */
231      public final boolean hasUninterruptibleNoWarnAnnotation() {
232        return isAnnotationDeclared(TypeReference.UninterruptibleNoWarn);
233      }
234    
235      /**
236       * Return true if this element has a UninterruptibleNoWarn annotation.
237       * @see org.vmmagic.pragma.UninterruptibleNoWarn
238       */
239      public final boolean hasUnpreemptibleNoWarnAnnotation() {
240        return isAnnotationDeclared(TypeReference.UnpreemptibleNoWarn);
241      }
242    
243      /**
244       * Return true if this element has a Uninterruptible annotation.
245       * @see org.vmmagic.pragma.Uninterruptible
246       */
247      public final boolean hasUninterruptibleAnnotation() {
248        return isAnnotationDeclared(TypeReference.Uninterruptible);
249      }
250      /**
251       * Return true if this element has a NoCheckStore annotation.
252       * @see org.vmmagic.pragma.NoCheckStore
253       */
254      public final boolean hasNoCheckStoreAnnotation() {
255        return isAnnotationDeclared(TypeReference.NoCheckStore);
256      }
257    
258      /**
259       * Return true if this element has a Unpreemptible annotation.
260       * @see org.vmmagic.pragma.Unpreemptible
261       */
262      public final boolean hasUnpreemptibleAnnotation() {
263        return isAnnotationDeclared(TypeReference.Unpreemptible);
264      }
265    
266      /**
267       * Return true if this element has a NoOptCompile annotation.
268       * @see org.vmmagic.pragma.NoOptCompile
269       */
270      public final boolean hasNoOptCompileAnnotation() {
271        return isAnnotationPresent(org.vmmagic.pragma.NoOptCompile.class);
272      }
273    
274      /**
275       * Return true if this element has a Inline annotation.
276       * @see org.vmmagic.pragma.Inline
277       */
278      public final boolean hasInlineAnnotation() {
279        return isAnnotationPresent(org.vmmagic.pragma.Inline.class);
280      }
281    
282      /**
283       * Return true if this element has a NoInline annotation.
284       * @see org.vmmagic.pragma.NoInline
285       */
286      public final boolean hasNoInlineAnnotation() {
287        return isAnnotationPresent(org.vmmagic.pragma.NoInline.class);
288      }
289    
290      /**
291       * Return true if this element has a BaselineNoRegisters annotation.
292       * @see org.vmmagic.pragma.BaselineNoRegisters
293       */
294      public final boolean hasBaselineNoRegistersAnnotation() {
295        return isAnnotationDeclared(TypeReference.BaselineNoRegisters);
296      }
297    
298      /**
299       * Return true if this element has a BaselineSaveLSRegisters annotation.
300       * @see org.vmmagic.pragma.BaselineSaveLSRegisters
301       */
302      @Uninterruptible
303      public final boolean hasBaselineSaveLSRegistersAnnotation() {
304        return isAnnotationDeclared(TypeReference.BaselineSaveLSRegisters);
305      }
306    
307      /**
308       * Return true if this element has a Pure annotation.
309       * @see org.vmmagic.pragma.Pure
310       */
311      public final boolean hasPureAnnotation() {
312        return isAnnotationPresent(org.vmmagic.pragma.Pure.class);
313      }
314    
315      /**
316       * Return true if this element has a RuntimePure annotation.
317       * @see org.vmmagic.pragma.RuntimePure
318       */
319      public final boolean hasRuntimePureAnnotation() {
320        return isAnnotationPresent(org.vmmagic.pragma.RuntimePure.class);
321      }
322    
323      /**
324       * Return true if this element has a NoNullCheck annotation.
325       * @see org.vmmagic.pragma.NoNullCheck
326       */
327      public final boolean hasNoNullCheckAnnotation() {
328        return isAnnotationPresent(org.vmmagic.pragma.NoNullCheck.class);
329      }
330    
331      /**
332       * Return true if this element has a NoBoundsCheck annotation.
333       * @see org.vmmagic.pragma.NoBoundsCheck
334       */
335      public final boolean hasNoBoundsCheckAnnotation() {
336        return isAnnotationPresent(org.vmmagic.pragma.NoBoundsCheck.class);
337      }
338    
339      /**
340       * Return true if this element has a RuntimeFinal annotation.
341       * @see org.vmmagic.pragma.RuntimeFinal
342       */
343      public final boolean hasRuntimeFinalAnnotation() {
344        return isAnnotationPresent(org.vmmagic.pragma.RuntimeFinal.class);
345      }
346    
347      /**
348       * Return true if this element has a NoEscapes annotation.
349       * @see org.vmmagic.pragma.NoEscapes
350       */
351      public final boolean hasNoEscapesAnnotation() {
352        return isAnnotationPresent(org.vmmagic.pragma.NoEscapes.class);
353      }
354    
355      /**
356       * Return true if this element has a Untraced annotation.
357       * @see org.vmmagic.pragma.Untraced
358       */
359      public final boolean hasUntracedAnnotation() {
360        return isAnnotationDeclared(TypeReference.Untraced);
361      }
362    
363      /**
364       * Return true if this element has a NonMoving annotation.
365       * @see org.vmmagic.pragma.NonMoving
366       */
367      public final boolean hasNonMovingAnnotation() {
368        return isAnnotationDeclared(TypeReference.NonMoving);
369      }
370    
371      /**
372       * Return true if this element has a NonMovingAllocation annotation.
373       * @see org.vmmagic.pragma.NonMovingAllocation
374       */
375      public final boolean hasNonMovingAllocationAnnotation() {
376        return isAnnotationDeclared(TypeReference.NonMovingAllocation);
377      }
378    }