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.compilers.opt; 014 015 import java.lang.reflect.Field; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.SizeConstants; 018 import org.jikesrvm.classloader.RVMField; 019 import org.jikesrvm.classloader.RVMType; 020 import org.jikesrvm.classloader.TypeReference; 021 import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 022 import org.jikesrvm.compilers.opt.ir.operand.ClassConstantOperand; 023 import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand; 024 import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand; 025 import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand; 026 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 027 import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 028 import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand; 029 import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand; 030 import org.jikesrvm.compilers.opt.ir.operand.StringConstantOperand; 031 import org.jikesrvm.runtime.Magic; 032 import org.jikesrvm.runtime.Statics; 033 import org.vmmagic.unboxed.Address; 034 import org.vmmagic.unboxed.Extent; 035 import org.vmmagic.unboxed.Offset; 036 import 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 */ 044 public abstract class StaticFieldReader implements SizeConstants { 045 046 /** 047 * Read the field from obj and return as the appropriate constant 048 */ 049 public static ConstantOperand getFieldValueAsConstant(RVMField field, Object obj) throws NoSuchFieldException { 050 if (VM.VerifyAssertions) VM._assert(field.isFinal(), "Error reading field " + field); 051 if (VM.VerifyAssertions) { 052 VM._assert(field.getDeclaringClass().isInitialized() || field.getDeclaringClass().isInBootImage(), 053 "Error reading field " + field); 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 throw new NoSuchFieldException(field.toString()); 135 } catch (IllegalAccessException e) { 136 throw new NoSuchFieldException(field.toString()); 137 } catch (NoSuchFieldError e) { 138 throw new NoSuchFieldException(field.toString()); 139 } catch (ClassNotFoundException e) { 140 throw new NoSuchFieldException(field.toString()); 141 } catch (NoClassDefFoundError e) { 142 throw new NoSuchFieldException(field.toString()); 143 } catch (IllegalAccessError e) { 144 throw new NoSuchFieldException(field.toString()); 145 } 146 } 147 } 148 149 /** 150 * Returns a constant operand with the current value of a static field. 151 * 152 * @param field the static field whose current value we want to read 153 * @return a constant operand representing the current value of the field. 154 */ 155 public static ConstantOperand getStaticFieldValue(RVMField field) throws NoSuchFieldException { 156 if (VM.VerifyAssertions) VM._assert(field.isFinal(), "Error reading field " + field); 157 if (VM.VerifyAssertions) VM._assert(field.isStatic(), "Error reading field " + field); 158 if (VM.VerifyAssertions) { 159 VM._assert(field.getDeclaringClass().isInitialized() || field.getDeclaringClass().isInBootImage(), 160 "Error reading field " + field); 161 } 162 163 TypeReference fieldType = field.getType(); 164 Offset off = field.getOffset(); 165 if ((fieldType == TypeReference.Address) || 166 (fieldType == TypeReference.Word) || 167 (fieldType == TypeReference.Offset) || 168 (fieldType == TypeReference.Extent)) { 169 Address val = getAddressStaticFieldValue(field); 170 return new AddressConstantOperand(val); 171 } else if (fieldType.isIntLikeType()) { 172 int val = getIntStaticFieldValue(field); 173 return new IntConstantOperand(val); 174 } else if (fieldType.isLongType()) { 175 long val = getLongStaticFieldValue(field); 176 return new LongConstantOperand(val, off); 177 } else if (fieldType.isFloatType()) { 178 float val = getFloatStaticFieldValue(field); 179 return new FloatConstantOperand(val, off); 180 } else if (fieldType.isDoubleType()) { 181 double val = getDoubleStaticFieldValue(field); 182 return new DoubleConstantOperand(val, off); 183 } else { // Reference type 184 if (VM.VerifyAssertions) VM._assert(fieldType.isReferenceType()); 185 Object val = getObjectStaticFieldValue(field); 186 if (val == null) { 187 return new NullConstantOperand(); 188 } else if (fieldType == TypeReference.JavaLangString) { 189 return new StringConstantOperand((String) val, off); 190 } else if (fieldType == TypeReference.JavaLangClass) { 191 Class<?> klass = (Class<?>) getObjectStaticFieldValue(field); 192 RVMType type; 193 if (VM.runningVM) { 194 type = java.lang.JikesRVMSupport.getTypeForClass(klass); 195 } else { 196 type = TypeReference.findOrCreate(klass).resolve(); 197 } 198 return new ClassConstantOperand(type.getClassForType(), off); 199 } else { 200 return new ObjectConstantOperand(val, off); 201 } 202 } 203 } 204 205 /** 206 * Returns the current contents of an int-like static field. 207 * 208 * @param field a static field 209 * @return the current value of the field 210 */ 211 public static int getIntStaticFieldValue(RVMField field) throws NoSuchFieldException { 212 if (VM.runningVM) { 213 return Statics.getSlotContentsAsInt(field.getOffset()); 214 } else { 215 try { 216 Field f = getJDKField(field); 217 TypeReference fieldType = field.getType(); 218 if (fieldType.isBooleanType()) { 219 boolean val = f.getBoolean(null); 220 return val ? 1 : 0; 221 } else if (fieldType.isByteType()) { 222 return f.getByte(null); 223 } else if (fieldType.isShortType()) { 224 return f.getShort(null); 225 } else if (fieldType.isIntType()) { 226 return f.getInt(null); 227 } else if (fieldType.isCharType()) { 228 return f.getChar(null); 229 } else { 230 throw new OptimizingCompilerException("Unsupported type " + field + "\n"); 231 } 232 } catch (IllegalAccessException e) { 233 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 234 } catch (IllegalArgumentException e) { 235 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 236 } 237 } 238 } 239 240 /** 241 * Returns the current contents of a float static field. 242 * 243 * @param field a static field 244 * @return the current value of the field 245 */ 246 public static float getFloatStaticFieldValue(RVMField field) throws NoSuchFieldException { 247 if (VM.runningVM) { 248 int bits = Statics.getSlotContentsAsInt(field.getOffset()); 249 return Magic.intBitsAsFloat(bits); 250 } else { 251 try { 252 return getJDKField(field).getFloat(null); 253 } catch (IllegalAccessException e) { 254 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 255 } catch (IllegalArgumentException e) { 256 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 257 } 258 } 259 } 260 261 /** 262 * Returns the current contents of a long static field. 263 * 264 * @param field a static field 265 * @return the current value of the field 266 */ 267 public static long getLongStaticFieldValue(RVMField field) throws NoSuchFieldException { 268 if (VM.runningVM) { 269 return Statics.getSlotContentsAsLong(field.getOffset()); 270 } else { 271 try { 272 return getJDKField(field).getLong(null); 273 } catch (IllegalAccessException e) { 274 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 275 } catch (IllegalArgumentException e) { 276 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 277 } 278 } 279 } 280 281 /** 282 * Returns the current contents of a double static field. 283 * 284 * @param field a static field 285 * @return the current value of the field 286 */ 287 public static double getDoubleStaticFieldValue(RVMField field) throws NoSuchFieldException { 288 if (VM.runningVM) { 289 long bits = Statics.getSlotContentsAsLong(field.getOffset()); 290 return Magic.longBitsAsDouble(bits); 291 } else { 292 try { 293 return getJDKField(field).getDouble(null); 294 } catch (IllegalAccessException e) { 295 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 296 } catch (IllegalArgumentException e) { 297 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 298 } 299 } 300 } 301 302 /** 303 * Returns the current contents of a reference static field. 304 * 305 * @param field a static field 306 * @return the current value of the field 307 */ 308 public static Object getObjectStaticFieldValue(RVMField field) throws NoSuchFieldException { 309 if (VM.runningVM) { 310 return Statics.getSlotContentsAsObject(field.getOffset()); 311 } else { 312 try { 313 return getJDKField(field).get(null); 314 } catch (IllegalAccessException e) { 315 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 316 } catch (IllegalArgumentException e) { 317 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 318 } 319 } 320 } 321 322 /** 323 * Returns the current contents of a Address static field. 324 * 325 * @param field a static field 326 * @return the current value of the field 327 */ 328 public static Address getAddressStaticFieldValue(RVMField field) throws NoSuchFieldException { 329 if (VM.runningVM) { 330 return Statics.getSlotContentsAsAddress(field.getOffset()); 331 } else { 332 try { 333 Object unboxed = getJDKField(field).get(null); 334 if (unboxed instanceof Address) { 335 return (Address) unboxed; 336 } else if (unboxed instanceof Word) { 337 return ((Word) unboxed).toAddress(); 338 } else if (unboxed instanceof Extent) { 339 return ((Extent) unboxed).toWord().toAddress(); 340 } else if (unboxed instanceof Offset) { 341 return ((Offset) unboxed).toWord().toAddress(); 342 } else { 343 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 344 return Address.zero(); 345 } 346 } catch (IllegalAccessException e) { 347 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 348 } catch (IllegalArgumentException e) { 349 throw new OptimizingCompilerException("Accessing " + field + " caused " + e); 350 } 351 } 352 } 353 354 /** 355 * Does a static field null contain {@code null}? 356 * 357 * @param field a static field 358 * @return {@code true} if the field contains {@code null}, {@code false} otherwise 359 */ 360 public static boolean isStaticFieldNull(RVMField field) throws NoSuchFieldException { 361 return getObjectStaticFieldValue(field) == null; 362 } 363 364 /** 365 * Get the type of an object contained in a static field. 366 * 367 * @param field a static field 368 * @return type of value contained in the field 369 */ 370 public static TypeReference getTypeFromStaticField(RVMField field) throws NoSuchFieldException { 371 Object o = getObjectStaticFieldValue(field); 372 if (o == null) return TypeReference.NULL_TYPE; 373 if (VM.runningVM) { 374 return Magic.getObjectType(o).getTypeRef(); 375 } else { 376 return TypeReference.findOrCreate(o.getClass()); 377 } 378 } 379 380 /** 381 * Utilitiy to convert a RVMField to a java.lang.reflect.Field 382 */ 383 private static Field getJDKField(RVMField field) throws NoSuchFieldException { 384 try { 385 String cn = field.getDeclaringClass().toString(); 386 if (VM.BuildForGnuClasspath && 387 field.getDeclaringClass().getClassForType().equals(java.lang.reflect.Proxy.class) && 388 field.getName().toString().equals("proxyClasses")) { 389 // Avoid confusing bootstrap JVM and classpath fields 390 throw new NoSuchFieldException(field.toString()); 391 } 392 Field f = Class.forName(cn).getDeclaredField(field.getName().toString()); 393 f.setAccessible(true); 394 return f; 395 } catch (NoSuchFieldError e) { 396 throw new NoSuchFieldException(field.toString()); 397 } catch (ClassNotFoundException e) { 398 throw new NoSuchFieldException(field.toString()); 399 } catch (NoClassDefFoundError e) { 400 throw new NoSuchFieldException(field.toString()); 401 } catch (IllegalAccessError e) { 402 throw new NoSuchFieldException(field.toString()); 403 } catch (UnsatisfiedLinkError e) { 404 throw new NoSuchFieldException(field.toString()); 405 } 406 } 407 }