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