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.compilers.opt; 014 015import java.lang.reflect.Field; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.classloader.RVMField; 019import org.jikesrvm.classloader.RVMType; 020import org.jikesrvm.classloader.TypeReference; 021import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 022import org.jikesrvm.compilers.opt.ir.operand.ClassConstantOperand; 023import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand; 024import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand; 025import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand; 026import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 027import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 028import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand; 029import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand; 030import org.jikesrvm.compilers.opt.ir.operand.StringConstantOperand; 031import org.jikesrvm.runtime.Magic; 032import org.jikesrvm.runtime.Statics; 033import org.vmmagic.unboxed.Address; 034import org.vmmagic.unboxed.Extent; 035import org.vmmagic.unboxed.Offset; 036import org.vmmagic.unboxed.Word; 037 038/** 039 * Code for accessing the value of a static field at 040 * compile time. This is used to optimize 041 * getstatic's of initialized static fields 042 * by replacing the getstatic with a constant operand. 043 */ 044public abstract class StaticFieldReader { 045 046 public static ConstantOperand getFieldValueAsConstant(RVMField field, Object obj) throws NoSuchFieldException { 047 if (VM.VerifyAssertions) { 048 boolean isFinalField = field.isFinal(); 049 boolean isInitializedField = field.getDeclaringClass().isInitialized() || field.getDeclaringClass().isInBootImage(); 050 if (!(isFinalField && isInitializedField)) { 051 String msg = "Error reading field " + field; 052 VM._assert(VM.NOT_REACHED, msg); 053 } 054 } 055 056 TypeReference type = field.getType(); 057 if (VM.runningVM) { 058 if (type.isReferenceType() && (!type.isMagicType() || type.isUnboxedArrayType())) { 059 Object value = field.getObjectValueUnchecked(obj); 060 if (value != null) { 061 return new ObjectConstantOperand(value, Offset.zero()); 062 } else { 063 return new NullConstantOperand(); 064 } 065 } else if (type.isWordLikeType()) { 066 return new AddressConstantOperand(field.getWordValueUnchecked(obj).toAddress()); 067 } else if (type.isIntType()) { 068 return new IntConstantOperand(field.getIntValueUnchecked(obj)); 069 } else if (type.isBooleanType()) { 070 return new IntConstantOperand(field.getBooleanValueUnchecked(obj) ? 1 : 0); 071 } else if (type.isByteType()) { 072 return new IntConstantOperand(field.getByteValueUnchecked(obj)); 073 } else if (type.isCharType()) { 074 return new IntConstantOperand(field.getCharValueUnchecked(obj)); 075 } else if (type.isDoubleType()) { 076 return new DoubleConstantOperand(field.getDoubleValueUnchecked(obj)); 077 } else if (type.isFloatType()) { 078 return new FloatConstantOperand(field.getFloatValueUnchecked(obj)); 079 } else if (type.isLongType()) { 080 return new LongConstantOperand(field.getLongValueUnchecked(obj)); 081 } else if (type.isShortType()) { 082 return new IntConstantOperand(field.getShortValueUnchecked(obj)); 083 } else { 084 OptimizingCompilerException.UNREACHABLE("Unknown type " + type); 085 return null; 086 } 087 } else { 088 try { 089 String cn = field.getDeclaringClass().toString(); 090 Field f = Class.forName(cn).getDeclaredField(field.getName().toString()); 091 f.setAccessible(true); 092 if (type.isReferenceType() && (!type.isMagicType() || type.isUnboxedArrayType())) { 093 Object value = f.get(obj); 094 if (value != null) { 095 return new ObjectConstantOperand(value, Offset.zero()); 096 } else { 097 return new NullConstantOperand(); 098 } 099 } else if (type.isWordLikeType()) { 100 Object value = f.get(obj); 101 if (type.equals(TypeReference.Word)) 102 return new AddressConstantOperand((Word)value); 103 else if (type.equals(TypeReference.Address)) 104 return new AddressConstantOperand((Address)value); 105 else if (type.equals(TypeReference.Offset)) 106 return new AddressConstantOperand((Offset)value); 107 else if (type.equals(TypeReference.Extent)) 108 return new AddressConstantOperand((Extent)value); 109 else { 110 OptimizingCompilerException.UNREACHABLE("Unknown word type " + type); 111 return null; 112 } 113 } else if (type.isIntType()) { 114 return new IntConstantOperand(f.getInt(obj)); 115 } else if (type.isBooleanType()) { 116 return new IntConstantOperand(f.getBoolean(obj) ? 1 : 0); 117 } else if (type.isByteType()) { 118 return new IntConstantOperand(f.getByte(obj)); 119 } else if (type.isCharType()) { 120 return new IntConstantOperand(f.getChar(obj)); 121 } else if (type.isDoubleType()) { 122 return new DoubleConstantOperand(f.getDouble(obj)); 123 } else if (type.isFloatType()) { 124 return new FloatConstantOperand(f.getFloat(obj)); 125 } else if (type.isLongType()) { 126 return new LongConstantOperand(f.getLong(obj)); 127 } else if (type.isShortType()) { 128 return new IntConstantOperand(f.getShort(obj)); 129 } else { 130 OptimizingCompilerException.UNREACHABLE(cn + "." + f.getName() + " has unknown type " + type); 131 return null; 132 } 133 } catch (IllegalArgumentException e) { 134 throwNoSuchFieldExceptionWithCause(field, e); 135 } catch (IllegalAccessException e) { 136 throwNoSuchFieldExceptionWithCause(field, e); 137 } catch (NoSuchFieldError e) { 138 throwNoSuchFieldExceptionWithCause(field, e); 139 } catch (ClassNotFoundException e) { 140 throwNoSuchFieldExceptionWithCause(field, e); 141 } catch (NoClassDefFoundError e) { 142 throwNoSuchFieldExceptionWithCause(field, e); 143 } catch (IllegalAccessError e) { 144 throwNoSuchFieldExceptionWithCause(field, e); 145 } 146 assertNotReached(); 147 return null; 148 } 149 } 150 151 /** 152 * Returns a constant operand with the current value of a static field. 153 * 154 * @param field the static field whose current value we want to read 155 * @return a constant operand representing the current value of the field. 156 * @throws NoSuchFieldException when the field could not be found 157 */ 158 public static ConstantOperand getStaticFieldValue(RVMField field) throws NoSuchFieldException { 159 if (VM.VerifyAssertions) { 160 boolean fieldIsReady = field.getDeclaringClass().isInitialized() || 161 field.getDeclaringClass().isInBootImage(); 162 boolean isFinalField = field.isFinal(); 163 boolean isStaticField = field.isStatic(); 164 if (!(isFinalField && isStaticField && fieldIsReady)) { 165 String msg = "Error reading field " + field; 166 VM._assert(VM.NOT_REACHED, msg); 167 } 168 } 169 170 TypeReference fieldType = field.getType(); 171 Offset off = field.getOffset(); 172 if ((fieldType == TypeReference.Address) || 173 (fieldType == TypeReference.Word) || 174 (fieldType == TypeReference.Offset) || 175 (fieldType == TypeReference.Extent)) { 176 Address val = getAddressStaticFieldValue(field); 177 return new AddressConstantOperand(val); 178 } else if (fieldType.isIntLikeType()) { 179 int val = getIntStaticFieldValue(field); 180 return new IntConstantOperand(val); 181 } else if (fieldType.isLongType()) { 182 long val = getLongStaticFieldValue(field); 183 return new LongConstantOperand(val); 184 } else if (fieldType.isFloatType()) { 185 float val = getFloatStaticFieldValue(field); 186 return new FloatConstantOperand(val, off); 187 } else if (fieldType.isDoubleType()) { 188 double val = getDoubleStaticFieldValue(field); 189 return new DoubleConstantOperand(val, off); 190 } else { // Reference type 191 if (VM.VerifyAssertions) VM._assert(fieldType.isReferenceType()); 192 Object val = getObjectStaticFieldValue(field); 193 if (val == null) { 194 return new NullConstantOperand(); 195 } else if (fieldType == TypeReference.JavaLangString) { 196 return new StringConstantOperand((String) val, off); 197 } else if (fieldType == TypeReference.JavaLangClass) { 198 Class<?> klass = (Class<?>) getObjectStaticFieldValue(field); 199 RVMType type; 200 if (VM.runningVM) { 201 type = java.lang.JikesRVMSupport.getTypeForClass(klass); 202 } else { 203 type = TypeReference.findOrCreate(klass).resolve(); 204 } 205 return new ClassConstantOperand(type.getClassForType(), off); 206 } else { 207 return new ObjectConstantOperand(val, off); 208 } 209 } 210 } 211 212 /** 213 * Returns the current contents of an int-like static field. 214 * 215 * @param field a static field 216 * @return the current value of the field 217 * @throws NoSuchFieldException when the field could not be found 218 */ 219 public static int getIntStaticFieldValue(RVMField field) throws NoSuchFieldException { 220 if (VM.runningVM) { 221 return Statics.getSlotContentsAsInt(field.getOffset()); 222 } else { 223 try { 224 Field f = getJDKField(field); 225 TypeReference fieldType = field.getType(); 226 if (fieldType.isBooleanType()) { 227 boolean val = f.getBoolean(null); 228 return val ? 1 : 0; 229 } else if (fieldType.isByteType()) { 230 return f.getByte(null); 231 } else if (fieldType.isShortType()) { 232 return f.getShort(null); 233 } else if (fieldType.isIntType()) { 234 return f.getInt(null); 235 } else if (fieldType.isCharType()) { 236 return f.getChar(null); 237 } else { 238 throw new OptimizingCompilerException("Unsupported type " + field + "\n"); 239 } 240 } catch (IllegalAccessException e) { 241 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 242 } catch (IllegalArgumentException e) { 243 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 244 } 245 assertNotReached(); 246 return 0; 247 } 248 } 249 250 /** 251 * Returns the current contents of a float static field. 252 * 253 * @param field a static field 254 * @return the current value of the field 255 * @throws NoSuchFieldException when the field could not be found 256 */ 257 public static float getFloatStaticFieldValue(RVMField field) throws NoSuchFieldException { 258 if (VM.runningVM) { 259 int bits = Statics.getSlotContentsAsInt(field.getOffset()); 260 return Magic.intBitsAsFloat(bits); 261 } else { 262 try { 263 return getJDKField(field).getFloat(null); 264 } catch (IllegalAccessException e) { 265 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 266 } catch (IllegalArgumentException e) { 267 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 268 } 269 assertNotReached(); 270 return 0f; 271 } 272 } 273 274 /** 275 * Returns the current contents of a long static field. 276 * 277 * @param field a static field 278 * @return the current value of the field 279 * @throws NoSuchFieldException when the field could not be found 280 */ 281 public static long getLongStaticFieldValue(RVMField field) throws NoSuchFieldException { 282 if (VM.runningVM) { 283 return Statics.getSlotContentsAsLong(field.getOffset()); 284 } else { 285 try { 286 return getJDKField(field).getLong(null); 287 } catch (IllegalAccessException e) { 288 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 289 } catch (IllegalArgumentException e) { 290 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 291 } 292 assertNotReached(); 293 return 0L; 294 } 295 } 296 297 /** 298 * Returns the current contents of a double static field. 299 * 300 * @param field a static field 301 * @return the current value of the field 302 * @throws NoSuchFieldException when the field could not be found 303 */ 304 public static double getDoubleStaticFieldValue(RVMField field) throws NoSuchFieldException { 305 if (VM.runningVM) { 306 long bits = Statics.getSlotContentsAsLong(field.getOffset()); 307 return Magic.longBitsAsDouble(bits); 308 } else { 309 try { 310 return getJDKField(field).getDouble(null); 311 } catch (IllegalAccessException e) { 312 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 313 } catch (IllegalArgumentException e) { 314 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 315 } 316 assertNotReached(); 317 return 0d; 318 } 319 } 320 321 /** 322 * Returns the current contents of a reference static field. 323 * 324 * @param field a static field 325 * @return the current value of the field 326 * @throws NoSuchFieldException when the field could not be found 327 */ 328 public static Object getObjectStaticFieldValue(RVMField field) throws NoSuchFieldException { 329 if (VM.runningVM) { 330 return Statics.getSlotContentsAsObject(field.getOffset()); 331 } else { 332 try { 333 return getJDKField(field).get(null); 334 } catch (IllegalAccessException e) { 335 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 336 } catch (IllegalArgumentException e) { 337 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 338 } 339 assertNotReached(); 340 return null; 341 } 342 } 343 344 /** 345 * Returns the current contents of a Address static field. 346 * 347 * @param field a static field 348 * @return the current value of the field 349 * @throws NoSuchFieldException when the field could not be found 350 */ 351 public static Address getAddressStaticFieldValue(RVMField field) throws NoSuchFieldException { 352 if (VM.runningVM) { 353 return Statics.getSlotContentsAsAddress(field.getOffset()); 354 } else { 355 try { 356 Object unboxed = getJDKField(field).get(null); 357 if (unboxed instanceof Address) { 358 return (Address) unboxed; 359 } else if (unboxed instanceof Word) { 360 return ((Word) unboxed).toAddress(); 361 } else if (unboxed instanceof Extent) { 362 return ((Extent) unboxed).toWord().toAddress(); 363 } else if (unboxed instanceof Offset) { 364 return ((Offset) unboxed).toWord().toAddress(); 365 } else { 366 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 367 return Address.zero(); 368 } 369 } catch (IllegalAccessException e) { 370 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 371 } catch (IllegalArgumentException e) { 372 throwOptimizingCompilerExceptionBecauseOfIllegalAccess(field, e); 373 } 374 assertNotReached(); 375 return Address.zero(); 376 } 377 } 378 379 /** 380 * Does a static field null contain {@code null}? 381 * 382 * @param field a static field 383 * @return {@code true} if the field contains {@code null}, {@code false} otherwise 384 * @throws NoSuchFieldException when the field could not be found 385 */ 386 public static boolean isStaticFieldNull(RVMField field) throws NoSuchFieldException { 387 return getObjectStaticFieldValue(field) == null; 388 } 389 390 /** 391 * Get the type of an object contained in a static field. 392 * 393 * @param field a static field 394 * @return type of value contained in the field 395 * @throws NoSuchFieldException when the field could not be found 396 */ 397 public static TypeReference getTypeFromStaticField(RVMField field) throws NoSuchFieldException { 398 Object o = getObjectStaticFieldValue(field); 399 if (o == null) return TypeReference.NULL_TYPE; 400 if (VM.runningVM) { 401 return Magic.getObjectType(o).getTypeRef(); 402 } else { 403 return TypeReference.findOrCreate(o.getClass()); 404 } 405 } 406 407 /** 408 * Converts a RVMField to a java.lang.reflect.Field. 409 * 410 * @param field the internal field representation 411 * @return the java.lang field representation 412 * @throws NoSuchFieldException when the field could not be found 413 */ 414 private static Field getJDKField(RVMField field) throws NoSuchFieldException { 415 try { 416 String cn = field.getDeclaringClass().toString(); 417 if (VM.BuildForGnuClasspath && 418 field.getDeclaringClass().getClassForType().equals(java.lang.reflect.Proxy.class) && 419 field.getName().toString().equals("proxyClasses")) { 420 // Avoid confusing bootstrap JVM and classpath fields 421 throw new NoSuchFieldException(field.toString()); 422 } 423 Field f = Class.forName(cn).getDeclaredField(field.getName().toString()); 424 f.setAccessible(true); 425 return f; 426 } catch (NoSuchFieldError e) { 427 throwNoSuchFieldExceptionWithCause(field, e); 428 } catch (ClassNotFoundException e) { 429 throwNoSuchFieldExceptionWithCause(field, e); 430 } catch (NoClassDefFoundError e) { 431 throwNoSuchFieldExceptionWithCause(field, e); 432 } catch (IllegalAccessError e) { 433 throwNoSuchFieldExceptionWithCause(field, e); 434 } catch (UnsatisfiedLinkError e) { 435 throwNoSuchFieldExceptionWithCause(field, e); 436 } 437 assertNotReached(); 438 return null; 439 } 440 441 private static void throwOptimizingCompilerExceptionBecauseOfIllegalAccess( 442 RVMField field, Throwable e) { 443 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 444 } 445 446 private static void throwNoSuchFieldExceptionWithCause(RVMField field, Throwable cause) 447 throws NoSuchFieldException { 448 NoSuchFieldException e = new NoSuchFieldException(field.toString()); 449 e.initCause(cause); 450 throw e; 451 } 452 453 private static void assertNotReached() { 454 if (VM.VerifyAssertions) { 455 VM._assert(VM.NOT_REACHED, "Exception should have been thrown beforehand"); 456 } else { 457 VM.sysFail("An exception should have been thrown before this point was reached!"); 458 } 459 } 460 461}