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 made-traced reference? 159 */ 160 @Uninterruptible 161 public boolean madeTraced() { 162 return madeTraced; 163 } 164 165 166 /** 167 * Does the field hold a reference? 168 */ 169 public boolean isReferenceType() { 170 return reference; 171 } 172 173 /** 174 * Shared among all instances of this class? 175 */ 176 @Uninterruptible 177 public boolean isStatic() { 178 return (modifiers & ACC_STATIC) != 0; 179 } 180 181 /** 182 * May only be assigned once? 183 */ 184 @Uninterruptible 185 public boolean isFinal() { 186 return (modifiers & ACC_FINAL) != 0; 187 } 188 189 /** 190 * Value not to be cached in a register? 191 */ 192 @Uninterruptible 193 public boolean isVolatile() { 194 return (modifiers & ACC_VOLATILE) != 0; 195 } 196 197 /** 198 * Value not to be written/read by persistent object manager? 199 */ 200 @Uninterruptible 201 public boolean isTransient() { 202 return (modifiers & ACC_TRANSIENT) != 0; 203 } 204 205 /** 206 * Not present in source code file? 207 */ 208 public boolean isSynthetic() { 209 return (modifiers & ACC_SYNTHETIC) != 0; 210 } 211 212 /** 213 * Enum constant 214 */ 215 public boolean isEnumConstant() { 216 return (modifiers & ACC_ENUM) != 0; 217 } 218 219 /** 220 * Is the field RuntimeFinal? That is can the annotation value be used in 221 * place a reading the field. 222 * @return whether the method has a pure annotation 223 */ 224 public boolean isRuntimeFinal() { 225 return hasRuntimeFinalAnnotation(); 226 } 227 228 /** 229 * Is this field invisible to the memory management system. 230 */ 231 public boolean isUntraced() { 232 return hasUntracedAnnotation(); 233 } 234 235 /** 236 * Make this field a traced field by garbage collection. Affects all 237 * subclasses of the class in which this field is defined. 238 */ 239 public void makeTraced() { 240 madeTraced = true; 241 getDeclaringClass().makeFieldTraced(this); 242 } 243 244 /** 245 * Get the value from the runtime final field 246 * @return whether the method has a pure annotation 247 */ 248 public boolean getRuntimeFinalValue() { 249 org.vmmagic.pragma.RuntimeFinal ann; 250 if (VM.runningVM) { 251 ann = getAnnotation(org.vmmagic.pragma.RuntimeFinal.class); 252 } else { 253 try { 254 ann = getDeclaringClass().getClassForType().getField(getName().toString()) 255 .getAnnotation(org.vmmagic.pragma.RuntimeFinal.class); 256 } catch (NoSuchFieldException e) { 257 throw new Error(e); 258 } 259 } 260 return ann.value(); 261 } 262 263 /** 264 * Get index of constant pool entry containing this 265 * "static final constant" field's value. 266 * @return constant pool index (0 --> field is not a "static final constant") 267 */ 268 @Uninterruptible 269 int getConstantValueIndex() { 270 return constantValueIndex; 271 } 272 273 //-------------------------------------------------------------------// 274 // Low level support for various reflective operations // 275 // Because different clients have different error checking // 276 // requirements, these operations are completely unsafe and we // 277 // assume that the client has done the required error checking. // 278 //-------------------------------------------------------------------// 279 280 /** 281 * Read the contents of the field. 282 * If the contents of this field is an object, return that object. 283 * If the contents of this field is a primitive, get the value and wrap it in an object. 284 */ 285 public Object getObjectUnchecked(Object obj) { 286 if (isReferenceType()) { 287 return getObjectValueUnchecked(obj); 288 } else { 289 TypeReference type = getType(); 290 if (type.isCharType()) return getCharValueUnchecked(obj); 291 if (type.isDoubleType()) return getDoubleValueUnchecked(obj); 292 if (type.isFloatType()) return getFloatValueUnchecked(obj); 293 if (type.isLongType()) return getLongValueUnchecked(obj); 294 if (type.isIntType()) return getIntValueUnchecked(obj); 295 if (type.isShortType()) return getShortValueUnchecked(obj); 296 if (type.isByteType()) return getByteValueUnchecked(obj); 297 if (type.isBooleanType()) return getBooleanValueUnchecked(obj); 298 return null; 299 } 300 } 301 302 /** 303 * Read one object ref from heap using RVM object model, GC safe. 304 * @param obj the object whose field is to be read, 305 * or null if the field is static. 306 * @return the reference described by this RVMField from the given object. 307 */ 308 public Object getObjectValueUnchecked(Object obj) { 309 if (isStatic()) { 310 if (NEEDS_OBJECT_GETSTATIC_BARRIER && !isUntraced()) { 311 return Barriers.objectStaticRead(getOffset(), getId()); 312 } else { 313 return Statics.getSlotContentsAsObject(getOffset()); 314 } 315 } else { 316 if (NEEDS_OBJECT_GETFIELD_BARRIER && !isUntraced()) { 317 return Barriers.objectFieldRead(obj, getOffset(), getId()); 318 } else { 319 return Magic.getObjectAtOffset(obj, getOffset()); 320 } 321 } 322 } 323 324 public Word getWordValueUnchecked(Object obj) { 325 if (isStatic()) { 326 return Statics.getSlotContentsAsAddress(getOffset()).toWord(); 327 } else { 328 return Magic.getWordAtOffset(obj, getOffset()); 329 } 330 } 331 332 public Address getAddressValueUnchecked(Object obj) { 333 if (isStatic()) { 334 return Statics.getSlotContentsAsAddress(getOffset()).toWord().toAddress(); 335 } else { 336 return Magic.getAddressAtOffset(obj, getOffset()); 337 } 338 } 339 340 public Offset getOffsetValueUnchecked(Object obj) { 341 if (isStatic()) { 342 return Statics.getSlotContentsAsAddress(getOffset()).toWord().toOffset(); 343 } else { 344 return Magic.getOffsetAtOffset(obj, getOffset()); 345 } 346 } 347 348 public Extent getExtentValueUnchecked(Object obj) { 349 if (isStatic()) { 350 return Statics.getSlotContentsAsAddress(getOffset()).toWord().toExtent(); 351 } else { 352 return Magic.getExtentAtOffset(obj, getOffset()); 353 } 354 } 355 356 public boolean getBooleanValueUnchecked(Object obj) { 357 byte bits; 358 if (isStatic()) { 359 bits = (byte) Statics.getSlotContentsAsInt(getOffset()); 360 } else { 361 bits = Magic.getUnsignedByteAtOffset(obj, getOffset()); 362 } 363 return (bits != 0); 364 } 365 366 public byte getByteValueUnchecked(Object obj) { 367 if (isStatic()) { 368 return (byte) Statics.getSlotContentsAsInt(getOffset()); 369 } else { 370 return Magic.getByteAtOffset(obj, getOffset()); 371 } 372 } 373 374 public char getCharValueUnchecked(Object obj) { 375 if (isStatic()) { 376 return (char) Statics.getSlotContentsAsInt(getOffset()); 377 } else { 378 return Magic.getCharAtOffset(obj, getOffset()); 379 } 380 } 381 382 public short getShortValueUnchecked(Object obj) { 383 if (isStatic()) { 384 return (short) Statics.getSlotContentsAsInt(getOffset()); 385 } else { 386 return Magic.getShortAtOffset(obj, getOffset()); 387 } 388 } 389 390 public int getIntValueUnchecked(Object obj) { 391 return get32Bits(obj); 392 } 393 394 public long getLongValueUnchecked(Object obj) { 395 return get64Bits(obj); 396 } 397 398 public float getFloatValueUnchecked(Object obj) { 399 return Magic.intBitsAsFloat(get32Bits(obj)); 400 } 401 402 public double getDoubleValueUnchecked(Object obj) { 403 return Magic.longBitsAsDouble(get64Bits(obj)); 404 } 405 406 private int get32Bits(Object obj) { 407 if (isStatic()) { 408 return Statics.getSlotContentsAsInt(getOffset()); 409 } else { 410 return Magic.getIntAtOffset(obj, getOffset()); 411 } 412 } 413 414 private long get64Bits(Object obj) { 415 if (isStatic()) { 416 return Statics.getSlotContentsAsLong(getOffset()); 417 } else { 418 return Magic.getLongAtOffset(obj, getOffset()); 419 } 420 } 421 422 /** 423 * assign one object ref from heap using RVM object model, GC safe. 424 * @param obj the object whose field is to be modified, or null if the field is static. 425 * @param ref the object reference to be assigned. 426 */ 427 public void setObjectValueUnchecked(Object obj, Object ref) { 428 if (isStatic()) { 429 if (NEEDS_OBJECT_PUTSTATIC_BARRIER && !isUntraced()) { 430 Barriers.objectStaticWrite(ref, getOffset(), getId()); 431 } else { 432 Statics.setSlotContents(getOffset(), ref); 433 } 434 } else { 435 if (NEEDS_OBJECT_PUTFIELD_BARRIER && !isUntraced()) { 436 Barriers.objectFieldWrite(obj, ref, getOffset(), getId()); 437 } else { 438 Magic.setObjectAtOffset(obj, getOffset(), ref); 439 } 440 } 441 } 442 443 /** 444 * assign one object ref from heap using RVM object model, GC safe. 445 * @param obj the object whose field is to be modified, or null if the field is static. 446 * @param ref the object reference to be assigned. 447 */ 448 public void setWordValueUnchecked(Object obj, Word ref) { 449 if (isStatic()) { 450 Statics.setSlotContents(getOffset(), ref); 451 } else { 452 if (Barriers.NEEDS_WORD_PUTFIELD_BARRIER) { 453 Barriers.wordFieldWrite(obj, ref, getOffset(), getId()); 454 } else { 455 Magic.setWordAtOffset(obj, getOffset(), ref); 456 } 457 } 458 } 459 460 public void setAddressValueUnchecked(Object obj, Address ref) { 461 if (isStatic()) { 462 Statics.setSlotContents(getOffset(), ref); 463 } else { 464 if (Barriers.NEEDS_ADDRESS_PUTFIELD_BARRIER) { 465 Barriers.addressFieldWrite(obj, ref, getOffset(), getId()); 466 } else { 467 Magic.setAddressAtOffset(obj, getOffset(), ref); 468 } 469 } 470 } 471 472 public void setExtentValueUnchecked(Object obj, Extent ref) { 473 if (isStatic()) { 474 Statics.setSlotContents(getOffset(), ref); 475 } else { 476 if (Barriers.NEEDS_EXTENT_PUTFIELD_BARRIER) { 477 Barriers.extentFieldWrite(obj, ref, getOffset(), getId()); 478 } else { 479 Magic.setExtentAtOffset(obj, getOffset(), ref); 480 } 481 } 482 } 483 484 public void setOffsetValueUnchecked(Object obj, Offset ref) { 485 if (isStatic()) { 486 Statics.setSlotContents(getOffset(), ref); 487 } else { 488 if (Barriers.NEEDS_OFFSET_PUTFIELD_BARRIER) { 489 Barriers.offsetFieldWrite(obj, ref, getOffset(), getId()); 490 } else { 491 Magic.setOffsetAtOffset(obj, getOffset(), ref); 492 } 493 } 494 } 495 496 public void setBooleanValueUnchecked(Object obj, boolean b) { 497 if (isStatic()) { 498 Statics.setSlotContents(getOffset(), b ? 1 : 0); 499 } else { 500 if (Barriers.NEEDS_BOOLEAN_PUTFIELD_BARRIER) { 501 Barriers.booleanFieldWrite(obj, b, getOffset(), getId()); 502 } else { 503 Magic.setBooleanAtOffset(obj, getOffset(), b); 504 } 505 } 506 } 507 508 public void setByteValueUnchecked(Object obj, byte b) { 509 if (isStatic()) { 510 Statics.setSlotContents(getOffset(), b); 511 } else { 512 if (Barriers.NEEDS_BYTE_PUTFIELD_BARRIER) { 513 Barriers.byteFieldWrite(obj, b, getOffset(), getId()); 514 } else { 515 Magic.setByteAtOffset(obj, getOffset(), b); 516 } 517 } 518 } 519 520 public void setCharValueUnchecked(Object obj, char c) { 521 if (isStatic()) { 522 Statics.setSlotContents(getOffset(), c); 523 } else { 524 if (Barriers.NEEDS_CHAR_PUTFIELD_BARRIER) { 525 Barriers.charFieldWrite(obj, c, getOffset(), getId()); 526 } else { 527 Magic.setCharAtOffset(obj, getOffset(), c); 528 } 529 } 530 } 531 532 public void setShortValueUnchecked(Object obj, short i) { 533 if (isStatic()) { 534 Statics.setSlotContents(getOffset(), i); 535 } else { 536 if (Barriers.NEEDS_SHORT_PUTFIELD_BARRIER) { 537 Barriers.shortFieldWrite(obj, i, getOffset(), getId()); 538 } else { 539 Magic.setShortAtOffset(obj, getOffset(), i); 540 } 541 } 542 } 543 544 public void setIntValueUnchecked(Object obj, int i) { 545 if (isStatic()) { 546 Statics.setSlotContents(getOffset(), i); 547 } else { 548 if (Barriers.NEEDS_INT_PUTFIELD_BARRIER) { 549 Barriers.intFieldWrite(obj, i, getOffset(), getId()); 550 } else { 551 Magic.setIntAtOffset(obj, getOffset(), i); 552 } 553 } 554 } 555 556 public void setFloatValueUnchecked(Object obj, float f) { 557 if (isStatic()) { 558 Statics.setSlotContents(getOffset(), f); 559 } else { 560 if (Barriers.NEEDS_FLOAT_PUTFIELD_BARRIER) { 561 Barriers.floatFieldWrite(obj, f, getOffset(), getId()); 562 } else { 563 Magic.setFloatAtOffset(obj, getOffset(), f); 564 } 565 } 566 } 567 568 public void setLongValueUnchecked(Object obj, long l) { 569 if (isStatic()) { 570 Statics.setSlotContents(getOffset(), l); 571 } else { 572 if (Barriers.NEEDS_LONG_PUTFIELD_BARRIER) { 573 Barriers.longFieldWrite(obj, l, getOffset(), getId()); 574 } else { 575 Magic.setLongAtOffset(obj, getOffset(), l); 576 } 577 } 578 } 579 580 public void setDoubleValueUnchecked(Object obj, double d) { 581 if (isStatic()) { 582 Statics.setSlotContents(getOffset(), d); 583 } else { 584 if (Barriers.NEEDS_DOUBLE_PUTFIELD_BARRIER) { 585 Barriers.doubleFieldWrite(obj, d, getOffset(), getId()); 586 } else { 587 Magic.setDoubleAtOffset(obj, getOffset(), d); 588 } 589 } 590 } 591 }