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 org.jikesrvm.VM;
018 import org.jikesrvm.mm.mminterface.Barriers;
019 import org.jikesrvm.runtime.Magic;
020 import org.jikesrvm.runtime.Statics;
021 import org.vmmagic.pragma.Uninterruptible;
022 import org.vmmagic.unboxed.Address;
023 import org.vmmagic.unboxed.Extent;
024 import org.vmmagic.unboxed.Offset;
025 import org.vmmagic.unboxed.Word;
026 import static org.jikesrvm.mm.mminterface.Barriers.*;
027
028 /**
029 * A field of a java class.
030 */
031 public final class RVMField extends RVMMember {
032
033 /**
034 * constant pool index of field's value (0 --> not a "static final constant")
035 */
036 private final int constantValueIndex;
037
038 /**
039 * The size of the field in bytes
040 */
041 private final byte size;
042
043 /**
044 * Does the field hold a reference value?
045 */
046 private final boolean reference;
047
048 /**
049 * Has the field been made traced?
050 */
051 private boolean madeTraced;
052
053 /**
054 * Create a field.
055 *
056 * @param declaringClass the TypeReference object of the class
057 * that declared this field
058 * @param memRef the canonical memberReference for this member.
059 * @param modifiers modifiers associated with this field.
060 * @param signature generic type of this field.
061 * @param constantValueIndex constant pool index of constant value
062 * @param annotations array of runtime visible annotations
063 */
064 private RVMField(TypeReference declaringClass, MemberReference memRef, short modifiers, Atom signature,
065 int constantValueIndex, RVMAnnotation[] annotations) {
066 super(declaringClass, memRef, modifiers, signature, annotations);
067 this.constantValueIndex = constantValueIndex;
068 TypeReference typeRef = memRef.asFieldReference().getFieldContentsType();
069 this.size = (byte)typeRef.getMemoryBytes();
070 this.reference = typeRef.isReferenceType();
071 this.madeTraced = false;
072 if (VM.runningVM && isUntraced()) {
073 VM.sysFail("Untraced field " + toString() + " created at runtime!");
074 }
075 }
076
077 /**
078 * Read and create a field. NB only {@link RVMClass} is allowed to
079 * create an instance of a RVMField.
080 *
081 * @param declaringClass the TypeReference object of the class
082 * that declared this field
083 * @param constantPool the constant pool of the class loading this field
084 * @param memRef the canonical memberReference for this member.
085 * @param modifiers modifiers associated with this member.
086 * @param input the DataInputStream to read the field's attributed from
087 */
088 static RVMField readField(TypeReference declaringClass, int[] constantPool, MemberReference memRef,
089 short modifiers, DataInputStream input) throws IOException {
090 // Read the attributes, processing the "non-boring" ones
091 int cvi = 0;
092 Atom signature = null;
093 RVMAnnotation[] annotations = null;
094 for (int i = 0, n = input.readUnsignedShort(); i < n; ++i) {
095 Atom attName = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
096 int attLength = input.readInt();
097 if (attName == RVMClassLoader.constantValueAttributeName) {
098 cvi = input.readUnsignedShort();
099 } else if (attName == RVMClassLoader.syntheticAttributeName) {
100 modifiers |= ACC_SYNTHETIC;
101 } else if (attName == RVMClassLoader.signatureAttributeName) {
102 signature = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
103 } else if (attName == RVMClassLoader.runtimeVisibleAnnotationsAttributeName) {
104 annotations = AnnotatedElement.readAnnotations(constantPool, input, declaringClass.getClassLoader());
105 } else {
106 // all other attributes are boring...
107 int skippedAmount = input.skipBytes(attLength);
108 if (skippedAmount != attLength) {
109 throw new IOException("Unexpected short skip");
110 }
111 }
112 }
113 return new RVMField(declaringClass,
114 memRef,
115 (short) (modifiers & APPLICABLE_TO_FIELDS),
116 signature,
117 cvi,
118 annotations);
119 }
120
121 /**
122 * Create a field for a synthetic annotation class
123 */
124 static RVMField createAnnotationField(TypeReference annotationClass, MemberReference memRef) {
125 return new RVMField(annotationClass, memRef, (short) (ACC_PRIVATE | ACC_SYNTHETIC), null, 0, null);
126 }
127
128 /**
129 * Get type of this field's value.
130 */
131 @Uninterruptible
132 public TypeReference getType() {
133 return memRef.asFieldReference().getFieldContentsType();
134 }
135
136 /**
137 * How many stackslots do value of this type take?
138 */
139 public int getNumberOfStackSlots() {
140 return getType().getStackWords();
141 }
142
143 /**
144 * How many bytes of memory words do value of this type take?
145 */
146 public int getSize() {
147 return size;
148 }
149
150 /**
151 * Does the field hold a reference?
152 */
153 public boolean isTraced() {
154 return (reference && !isUntraced()) || madeTraced;
155 }
156
157 /**
158 * Does the field hold a reference?
159 */
160 public boolean isReferenceType() {
161 return reference;
162 }
163
164 /**
165 * Shared among all instances of this class?
166 */
167 @Uninterruptible
168 public boolean isStatic() {
169 return (modifiers & ACC_STATIC) != 0;
170 }
171
172 /**
173 * May only be assigned once?
174 */
175 @Uninterruptible
176 public boolean isFinal() {
177 return (modifiers & ACC_FINAL) != 0;
178 }
179
180 /**
181 * Value not to be cached in a register?
182 */
183 @Uninterruptible
184 public boolean isVolatile() {
185 return (modifiers & ACC_VOLATILE) != 0;
186 }
187
188 /**
189 * Value not to be written/read by persistent object manager?
190 */
191 @Uninterruptible
192 public boolean isTransient() {
193 return (modifiers & ACC_TRANSIENT) != 0;
194 }
195
196 /**
197 * Not present in source code file?
198 */
199 public boolean isSynthetic() {
200 return (modifiers & ACC_SYNTHETIC) != 0;
201 }
202
203 /**
204 * Enum constant
205 */
206 public boolean isEnumConstant() {
207 return (modifiers & ACC_ENUM) != 0;
208 }
209
210 /**
211 * Is the field RuntimeFinal? That is can the annotation value be used in
212 * place a reading the field.
213 * @return whether the method has a pure annotation
214 */
215 public boolean isRuntimeFinal() {
216 return hasRuntimeFinalAnnotation();
217 }
218
219 /**
220 * Is this field invisible to the memory management system.
221 */
222 public boolean isUntraced() {
223 return hasUntracedAnnotation();
224 }
225
226 /**
227 * Make this field a traced field by garbage collection. Affects all
228 * subclasses of the class in which this field is defined.
229 */
230 public void makeTraced() {
231 madeTraced = true;
232 getDeclaringClass().makeFieldTraced(this);
233 }
234
235 /**
236 * Get the value from the runtime final field
237 * @return whether the method has a pure annotation
238 */
239 public boolean getRuntimeFinalValue() {
240 org.vmmagic.pragma.RuntimeFinal ann;
241 if (VM.runningVM) {
242 ann = getAnnotation(org.vmmagic.pragma.RuntimeFinal.class);
243 } else {
244 try {
245 ann = getDeclaringClass().getClassForType().getField(getName().toString())
246 .getAnnotation(org.vmmagic.pragma.RuntimeFinal.class);
247 } catch (NoSuchFieldException e) {
248 throw new Error(e);
249 }
250 }
251 return ann.value();
252 }
253
254 /**
255 * Get index of constant pool entry containing this
256 * "static final constant" field's value.
257 * @return constant pool index (0 --> field is not a "static final constant")
258 */
259 @Uninterruptible
260 int getConstantValueIndex() {
261 return constantValueIndex;
262 }
263
264 //-------------------------------------------------------------------//
265 // Low level support for various reflective operations //
266 // Because different clients have different error checking //
267 // requirements, these operations are completely unsafe and we //
268 // assume that the client has done the required error checking. //
269 //-------------------------------------------------------------------//
270
271 /**
272 * Read the contents of the field.
273 * If the contents of this field is an object, return that object.
274 * If the contents of this field is a primitive, get the value and wrap it in an object.
275 */
276 public Object getObjectUnchecked(Object obj) {
277 if (isReferenceType()) {
278 return getObjectValueUnchecked(obj);
279 } else {
280 TypeReference type = getType();
281 if (type.isCharType()) return getCharValueUnchecked(obj);
282 if (type.isDoubleType()) return getDoubleValueUnchecked(obj);
283 if (type.isFloatType()) return getFloatValueUnchecked(obj);
284 if (type.isLongType()) return getLongValueUnchecked(obj);
285 if (type.isIntType()) return getIntValueUnchecked(obj);
286 if (type.isShortType()) return getShortValueUnchecked(obj);
287 if (type.isByteType()) return getByteValueUnchecked(obj);
288 if (type.isBooleanType()) return getBooleanValueUnchecked(obj);
289 return null;
290 }
291 }
292
293 /**
294 * Read one object ref from heap using RVM object model, GC safe.
295 * @param obj the object whose field is to be read,
296 * or null if the field is static.
297 * @return the reference described by this RVMField from the given object.
298 */
299 public Object getObjectValueUnchecked(Object obj) {
300 if (isStatic()) {
301 if (NEEDS_OBJECT_GETSTATIC_BARRIER && !isUntraced()) {
302 return Barriers.objectStaticRead(getOffset(), getId());
303 } else {
304 return Statics.getSlotContentsAsObject(getOffset());
305 }
306 } else {
307 if (NEEDS_OBJECT_GETFIELD_BARRIER && !isUntraced()) {
308 return Barriers.objectFieldRead(obj, getOffset(), getId());
309 } else {
310 return Magic.getObjectAtOffset(obj, getOffset());
311 }
312 }
313 }
314
315 public Word getWordValueUnchecked(Object obj) {
316 if (isStatic()) {
317 return Statics.getSlotContentsAsAddress(getOffset()).toWord();
318 } else {
319 return Magic.getWordAtOffset(obj, getOffset());
320 }
321 }
322
323 public Address getAddressValueUnchecked(Object obj) {
324 if (isStatic()) {
325 return Statics.getSlotContentsAsAddress(getOffset()).toWord().toAddress();
326 } else {
327 return Magic.getAddressAtOffset(obj, getOffset());
328 }
329 }
330
331 public Offset getOffsetValueUnchecked(Object obj) {
332 if (isStatic()) {
333 return Statics.getSlotContentsAsAddress(getOffset()).toWord().toOffset();
334 } else {
335 return Magic.getOffsetAtOffset(obj, getOffset());
336 }
337 }
338
339 public Extent getExtentValueUnchecked(Object obj) {
340 if (isStatic()) {
341 return Statics.getSlotContentsAsAddress(getOffset()).toWord().toExtent();
342 } else {
343 return Magic.getExtentAtOffset(obj, getOffset());
344 }
345 }
346
347 public boolean getBooleanValueUnchecked(Object obj) {
348 byte bits;
349 if (isStatic()) {
350 bits = (byte) Statics.getSlotContentsAsInt(getOffset());
351 } else {
352 bits = Magic.getUnsignedByteAtOffset(obj, getOffset());
353 }
354 return (bits != 0);
355 }
356
357 public byte getByteValueUnchecked(Object obj) {
358 if (isStatic()) {
359 return (byte) Statics.getSlotContentsAsInt(getOffset());
360 } else {
361 return Magic.getByteAtOffset(obj, getOffset());
362 }
363 }
364
365 public char getCharValueUnchecked(Object obj) {
366 if (isStatic()) {
367 return (char) Statics.getSlotContentsAsInt(getOffset());
368 } else {
369 return Magic.getCharAtOffset(obj, getOffset());
370 }
371 }
372
373 public short getShortValueUnchecked(Object obj) {
374 if (isStatic()) {
375 return (short) Statics.getSlotContentsAsInt(getOffset());
376 } else {
377 return Magic.getShortAtOffset(obj, getOffset());
378 }
379 }
380
381 public int getIntValueUnchecked(Object obj) {
382 return get32Bits(obj);
383 }
384
385 public long getLongValueUnchecked(Object obj) {
386 return get64Bits(obj);
387 }
388
389 public float getFloatValueUnchecked(Object obj) {
390 return Magic.intBitsAsFloat(get32Bits(obj));
391 }
392
393 public double getDoubleValueUnchecked(Object obj) {
394 return Magic.longBitsAsDouble(get64Bits(obj));
395 }
396
397 private int get32Bits(Object obj) {
398 if (isStatic()) {
399 return Statics.getSlotContentsAsInt(getOffset());
400 } else {
401 return Magic.getIntAtOffset(obj, getOffset());
402 }
403 }
404
405 private long get64Bits(Object obj) {
406 if (isStatic()) {
407 return Statics.getSlotContentsAsLong(getOffset());
408 } else {
409 return Magic.getLongAtOffset(obj, getOffset());
410 }
411 }
412
413 /**
414 * assign one object ref from heap using RVM object model, GC safe.
415 * @param obj the object whose field is to be modified, or null if the field is static.
416 * @param ref the object reference to be assigned.
417 */
418 public void setObjectValueUnchecked(Object obj, Object ref) {
419 if (isStatic()) {
420 if (NEEDS_OBJECT_PUTSTATIC_BARRIER && !isUntraced()) {
421 Barriers.objectStaticWrite(ref, getOffset(), getId());
422 } else {
423 Statics.setSlotContents(getOffset(), ref);
424 }
425 } else {
426 if (NEEDS_OBJECT_PUTFIELD_BARRIER && !isUntraced()) {
427 Barriers.objectFieldWrite(obj, ref, getOffset(), getId());
428 } else {
429 Magic.setObjectAtOffset(obj, getOffset(), ref);
430 }
431 }
432 }
433
434 /**
435 * assign one object ref from heap using RVM object model, GC safe.
436 * @param obj the object whose field is to be modified, or null if the field is static.
437 * @param ref the object reference to be assigned.
438 */
439 public void setWordValueUnchecked(Object obj, Word ref) {
440 if (isStatic()) {
441 Statics.setSlotContents(getOffset(), ref);
442 } else {
443 if (Barriers.NEEDS_WORD_PUTFIELD_BARRIER) {
444 Barriers.wordFieldWrite(obj, ref, getOffset(), getId());
445 } else {
446 Magic.setWordAtOffset(obj, getOffset(), ref);
447 }
448 }
449 }
450
451 public void setAddressValueUnchecked(Object obj, Address ref) {
452 if (isStatic()) {
453 Statics.setSlotContents(getOffset(), ref);
454 } else {
455 if (Barriers.NEEDS_ADDRESS_PUTFIELD_BARRIER) {
456 Barriers.addressFieldWrite(obj, ref, getOffset(), getId());
457 } else {
458 Magic.setAddressAtOffset(obj, getOffset(), ref);
459 }
460 }
461 }
462
463 public void setExtentValueUnchecked(Object obj, Extent ref) {
464 if (isStatic()) {
465 Statics.setSlotContents(getOffset(), ref);
466 } else {
467 if (Barriers.NEEDS_EXTENT_PUTFIELD_BARRIER) {
468 Barriers.extentFieldWrite(obj, ref, getOffset(), getId());
469 } else {
470 Magic.setExtentAtOffset(obj, getOffset(), ref);
471 }
472 }
473 }
474
475 public void setOffsetValueUnchecked(Object obj, Offset ref) {
476 if (isStatic()) {
477 Statics.setSlotContents(getOffset(), ref);
478 } else {
479 if (Barriers.NEEDS_OFFSET_PUTFIELD_BARRIER) {
480 Barriers.offsetFieldWrite(obj, ref, getOffset(), getId());
481 } else {
482 Magic.setOffsetAtOffset(obj, getOffset(), ref);
483 }
484 }
485 }
486
487 public void setBooleanValueUnchecked(Object obj, boolean b) {
488 if (isStatic()) {
489 Statics.setSlotContents(getOffset(), b ? 1 : 0);
490 } else {
491 if (Barriers.NEEDS_BOOLEAN_PUTFIELD_BARRIER) {
492 Barriers.booleanFieldWrite(obj, b, getOffset(), getId());
493 } else {
494 Magic.setBooleanAtOffset(obj, getOffset(), b);
495 }
496 }
497 }
498
499 public void setByteValueUnchecked(Object obj, byte b) {
500 if (isStatic()) {
501 Statics.setSlotContents(getOffset(), b);
502 } else {
503 if (Barriers.NEEDS_BYTE_PUTFIELD_BARRIER) {
504 Barriers.byteFieldWrite(obj, b, getOffset(), getId());
505 } else {
506 Magic.setByteAtOffset(obj, getOffset(), b);
507 }
508 }
509 }
510
511 public void setCharValueUnchecked(Object obj, char c) {
512 if (isStatic()) {
513 Statics.setSlotContents(getOffset(), c);
514 } else {
515 if (Barriers.NEEDS_CHAR_PUTFIELD_BARRIER) {
516 Barriers.charFieldWrite(obj, c, getOffset(), getId());
517 } else {
518 Magic.setCharAtOffset(obj, getOffset(), c);
519 }
520 }
521 }
522
523 public void setShortValueUnchecked(Object obj, short i) {
524 if (isStatic()) {
525 Statics.setSlotContents(getOffset(), i);
526 } else {
527 if (Barriers.NEEDS_SHORT_PUTFIELD_BARRIER) {
528 Barriers.shortFieldWrite(obj, i, getOffset(), getId());
529 } else {
530 Magic.setShortAtOffset(obj, getOffset(), i);
531 }
532 }
533 }
534
535 public void setIntValueUnchecked(Object obj, int i) {
536 if (isStatic()) {
537 Statics.setSlotContents(getOffset(), i);
538 } else {
539 if (Barriers.NEEDS_INT_PUTFIELD_BARRIER) {
540 Barriers.intFieldWrite(obj, i, getOffset(), getId());
541 } else {
542 Magic.setIntAtOffset(obj, getOffset(), i);
543 }
544 }
545 }
546
547 public void setFloatValueUnchecked(Object obj, float f) {
548 if (isStatic()) {
549 Statics.setSlotContents(getOffset(), f);
550 } else {
551 if (Barriers.NEEDS_FLOAT_PUTFIELD_BARRIER) {
552 Barriers.floatFieldWrite(obj, f, getOffset(), getId());
553 } else {
554 Magic.setFloatAtOffset(obj, getOffset(), f);
555 }
556 }
557 }
558
559 public void setLongValueUnchecked(Object obj, long l) {
560 if (isStatic()) {
561 Statics.setSlotContents(getOffset(), l);
562 } else {
563 if (Barriers.NEEDS_LONG_PUTFIELD_BARRIER) {
564 Barriers.longFieldWrite(obj, l, getOffset(), getId());
565 } else {
566 Magic.setLongAtOffset(obj, getOffset(), l);
567 }
568 }
569 }
570
571 public void setDoubleValueUnchecked(Object obj, double d) {
572 if (isStatic()) {
573 Statics.setSlotContents(getOffset(), d);
574 } else {
575 if (Barriers.NEEDS_DOUBLE_PUTFIELD_BARRIER) {
576 Barriers.doubleFieldWrite(obj, d, getOffset(), getId());
577 } else {
578 Magic.setDoubleAtOffset(obj, getOffset(), d);
579 }
580 }
581 }
582 }