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 }