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