/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt; import java.lang.reflect.Field; import org.jikesrvm.VM; import org.jikesrvm.VM_SizeConstants; import org.jikesrvm.classloader.VM_Field; import org.jikesrvm.classloader.VM_Type; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.ir.OPT_AddressConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_ClassConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_ConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_DoubleConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_FloatConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_LongConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_NullConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_ObjectConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_StringConstantOperand; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.runtime.VM_Statics; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; //TODO - Deal with Subarch /** * Code for accessing the value of a static field at * compile time. This is used to optimize * getstatic's of initialized static fields * by replacing the getstatic with a constant operand. */ public abstract class OPT_StaticFieldReader implements VM_SizeConstants { /** * Read the field from obj and return as the appropriate constant */ public static OPT_ConstantOperand getFieldValueAsConstant(VM_Field field, Object obj) throws NoSuchFieldException { if (VM.VerifyAssertions) VM._assert(field.isFinal(), "Error reading field " + field); if (VM.VerifyAssertions) { VM._assert(field.getDeclaringClass().isInitialized(false) || field.getDeclaringClass().isInBootImage(), "Error reading field " + field); } VM_TypeReference type = field.getType(); if (VM.runningVM) { if (type.isReferenceType() && !type.isMagicType()) { Object value = field.getObjectValueUnchecked(obj); if (value != null) { return new OPT_ObjectConstantOperand(value, Offset.zero()); } else { return new OPT_NullConstantOperand(); } } else if (type.isWordType()) { return new OPT_AddressConstantOperand(field.getWordValueUnchecked(obj).toAddress()); } else if (type.isIntType()) { return new OPT_IntConstantOperand(field.getIntValueUnchecked(obj)); } else if (type.isBooleanType()) { return new OPT_IntConstantOperand(field.getBooleanValueUnchecked(obj) ? 1 : 0); } else if (type.isByteType()) { return new OPT_IntConstantOperand(field.getByteValueUnchecked(obj)); } else if (type.isCharType()) { return new OPT_IntConstantOperand(field.getCharValueUnchecked(obj)); } else if (type.isDoubleType()) { return new OPT_DoubleConstantOperand(field.getDoubleValueUnchecked(obj)); } else if (type.isFloatType()) { return new OPT_FloatConstantOperand(field.getFloatValueUnchecked(obj)); } else if (type.isLongType()) { return new OPT_LongConstantOperand(field.getLongValueUnchecked(obj)); } else if (type.isShortType()) { return new OPT_IntConstantOperand(field.getShortValueUnchecked(obj)); } else { OPT_OptimizingCompilerException.UNREACHABLE("Unknown type " + type); return null; } } else { try { String cn = field.getDeclaringClass().toString(); Field f = Class.forName(cn).getDeclaredField(field.getName().toString()); f.setAccessible(true); if (type.isReferenceType() && !type.isMagicType()) { Object value = f.get(obj); if (value != null) { return new OPT_ObjectConstantOperand(value, Offset.zero()); } else { return new OPT_NullConstantOperand(); } } else if (type.isWordType()) { Object value = f.get(obj); if (type.equals(VM_TypeReference.Word)) return new OPT_AddressConstantOperand((Word)value); else if (type.equals(VM_TypeReference.Address)) return new OPT_AddressConstantOperand((Address)value); else if (type.equals(VM_TypeReference.Offset)) return new OPT_AddressConstantOperand((Offset)value); else if (type.equals(VM_TypeReference.Extent)) return new OPT_AddressConstantOperand((Extent)value); else { OPT_OptimizingCompilerException.UNREACHABLE("Unknown word type " + type); return null; } } else if (type.isIntType()) { return new OPT_IntConstantOperand(f.getInt(obj)); } else if (type.isBooleanType()) { return new OPT_IntConstantOperand(f.getBoolean(obj) ? 1 : 0); } else if (type.isByteType()) { return new OPT_IntConstantOperand(f.getByte(obj)); } else if (type.isCharType()) { return new OPT_IntConstantOperand(f.getChar(obj)); } else if (type.isDoubleType()) { return new OPT_DoubleConstantOperand(f.getDouble(obj)); } else if (type.isFloatType()) { return new OPT_FloatConstantOperand(f.getFloat(obj)); } else if (type.isLongType()) { return new OPT_LongConstantOperand(f.getLong(obj)); } else if (type.isShortType()) { return new OPT_IntConstantOperand(f.getShort(obj)); } else { OPT_OptimizingCompilerException.UNREACHABLE("Unknown type " + type); return null; } } catch (IllegalArgumentException e) { throw new NoSuchFieldException(field.toString()); } catch (IllegalAccessException e) { throw new NoSuchFieldException(field.toString()); } catch (NoSuchFieldError e) { throw new NoSuchFieldException(field.toString()); } catch (ClassNotFoundException e) { throw new NoSuchFieldException(field.toString()); } catch (NoClassDefFoundError e) { throw new NoSuchFieldException(field.toString()); } catch (IllegalAccessError e) { throw new NoSuchFieldException(field.toString()); } } } /** * Returns a constant operand with the current value of a static field. * * @param field the static field whose current value we want to read * @return a constant operand representing the current value of the field. */ public static OPT_ConstantOperand getStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.VerifyAssertions) VM._assert(field.isFinal(), "Error reading field " + field); if (VM.VerifyAssertions) VM._assert(field.isStatic(), "Error reading field " + field); if (VM.VerifyAssertions) { VM._assert(field.getDeclaringClass().isInitialized(false) || field.getDeclaringClass().isInBootImage(), "Error reading field " + field); } VM_TypeReference fieldType = field.getType(); Offset off = field.getOffset(); if ((fieldType == VM_TypeReference.Address) || (fieldType == VM_TypeReference.Word) || (fieldType == VM_TypeReference.Offset) || (fieldType == VM_TypeReference.Extent)) { Address val = getAddressStaticFieldValue(field); return new OPT_AddressConstantOperand(val); } else if (fieldType.isIntLikeType()) { int val = getIntStaticFieldValue(field); return new OPT_IntConstantOperand(val); } else if (fieldType.isLongType()) { long val = getLongStaticFieldValue(field); return new OPT_LongConstantOperand(val, off); } else if (fieldType.isFloatType()) { float val = getFloatStaticFieldValue(field); return new OPT_FloatConstantOperand(val, off); } else if (fieldType.isDoubleType()) { double val = getDoubleStaticFieldValue(field); return new OPT_DoubleConstantOperand(val, off); } else { // Reference type if (VM.VerifyAssertions) VM._assert(fieldType.isReferenceType()); Object val = getObjectStaticFieldValue(field); if (val == null) { return new OPT_NullConstantOperand(); } else if (fieldType == VM_TypeReference.JavaLangString) { return new OPT_StringConstantOperand((String) val, off); } else if (fieldType == VM_TypeReference.JavaLangClass) { Class<?> klass = (Class<?>) getObjectStaticFieldValue(field); VM_Type type; if (VM.runningVM) { type = java.lang.JikesRVMSupport.getTypeForClass(klass); } else { type = VM_TypeReference.findOrCreate(klass).resolve(false); } return new OPT_ClassConstantOperand(type.getClassForType(), off); } else { return new OPT_ObjectConstantOperand(val, off); } } } /** * Returns the current contents of an int-like static field. * * @param field a static field * @return the current value of the field */ public static int getIntStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.runningVM) { return VM_Statics.getSlotContentsAsInt(field.getOffset()); } else { try { Field f = getJDKField(field); VM_TypeReference fieldType = field.getType(); if (fieldType.isBooleanType()) { boolean val = f.getBoolean(null); return val ? 1 : 0; } else if (fieldType.isByteType()) { return f.getByte(null); } else if (fieldType.isShortType()) { return f.getShort(null); } else if (fieldType.isIntType()) { return f.getInt(null); } else if (fieldType.isCharType()) { return f.getChar(null); } else { throw new OPT_OptimizingCompilerException("Unsupported type " + field + "\n"); } } catch (IllegalAccessException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } catch (IllegalArgumentException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } } } /** * Returns the current contents of a float static field. * * @param field a static field * @return the current value of the field */ public static float getFloatStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.runningVM) { int bits = VM_Statics.getSlotContentsAsInt(field.getOffset()); return VM_Magic.intBitsAsFloat(bits); } else { try { return getJDKField(field).getFloat(null); } catch (IllegalAccessException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } catch (IllegalArgumentException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } } } /** * Returns the current contents of a long static field. * * @param field a static field * @return the current value of the field */ public static long getLongStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.runningVM) { return VM_Statics.getSlotContentsAsLong(field.getOffset()); } else { try { return getJDKField(field).getLong(null); } catch (IllegalAccessException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } catch (IllegalArgumentException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } } } /** * Returns the current contents of a double static field. * * @param field a static field * @return the current value of the field */ public static double getDoubleStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.runningVM) { long bits = VM_Statics.getSlotContentsAsLong(field.getOffset()); return VM_Magic.longBitsAsDouble(bits); } else { try { return getJDKField(field).getDouble(null); } catch (IllegalAccessException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } catch (IllegalArgumentException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } } } /** * Returns the current contents of a reference static field. * * @param field a static field * @return the current value of the field */ public static Object getObjectStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.runningVM) { return VM_Statics.getSlotContentsAsObject(field.getOffset()); } else { try { return getJDKField(field).get(null); } catch (IllegalAccessException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } catch (IllegalArgumentException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } } } /** * Returns the current contents of a Address static field. * * @param field a static field * @return the current value of the field */ public static Address getAddressStaticFieldValue(VM_Field field) throws NoSuchFieldException { if (VM.runningVM) { return VM_Statics.getSlotContentsAsAddress(field.getOffset()); } else { try { Object unboxed = getJDKField(field).get(null); if (unboxed instanceof Address) { return (Address) unboxed; } else if (unboxed instanceof Word) { return ((Word) unboxed).toAddress(); } else if (unboxed instanceof Extent) { return ((Extent) unboxed).toWord().toAddress(); } else if (unboxed instanceof Offset) { return ((Offset) unboxed).toWord().toAddress(); } else { if (VM.VerifyAssertions) VM._assert(false); return Address.zero(); } } catch (IllegalAccessException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } catch (IllegalArgumentException e) { throw new OPT_OptimizingCompilerException("Accessing " + field + " caused " + e); } } } /** * Does a static field null contain null? * * @param field a static field * @return true if the field contains null, false otherwise */ public static boolean isStaticFieldNull(VM_Field field) throws NoSuchFieldException { return getObjectStaticFieldValue(field) == null; } /** * Get the type of an object contained in a static field. * * @param field a static field * @return type of value contained in the field */ public static VM_TypeReference getTypeFromStaticField(VM_Field field) throws NoSuchFieldException { Object o = getObjectStaticFieldValue(field); if (o == null) return VM_TypeReference.NULL_TYPE; if (VM.runningVM) { return VM_Magic.getObjectType(o).getTypeRef(); } else { return VM_TypeReference.findOrCreate(o.getClass()); } } /** * Utilitiy to convert a VM_Field to a java.lang.reflect.Field */ private static Field getJDKField(VM_Field field) throws NoSuchFieldException { try { String cn = field.getDeclaringClass().toString(); Field f = Class.forName(cn).getDeclaredField(field.getName().toString()); f.setAccessible(true); return f; } catch (NoSuchFieldError e) { throw new NoSuchFieldException(field.toString()); } catch (ClassNotFoundException e) { throw new NoSuchFieldException(field.toString()); } catch (NoClassDefFoundError e) { throw new NoSuchFieldException(field.toString()); } catch (IllegalAccessError e) { throw new NoSuchFieldException(field.toString()); } } }