/* * 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.ir; import org.jikesrvm.VM; import org.jikesrvm.classloader.VM_Field; import org.jikesrvm.classloader.VM_FieldReference; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.OPT_ClassLoaderProxy; import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException; import org.vmmagic.unboxed.Offset; //TODO - Deal with Subarch /** * Represents a location in memory. Used to keep track of memory aliasing. * * @see OPT_Operand */ public final class OPT_LocationOperand extends OPT_Operand implements org.jikesrvm.compilers.opt.OPT_Constants { /* * TODO: Now that we don't pay a large penalty for dynamic type checks * of non-final classes, redesign this mess to have separate subclasses * of location operands for each type of memory access. * In the process, also switch to using synthetic VM_Fields * for the various pieces of the object header * (something like the following might work): * (VM_Field) VM.getMember("[I", "length", "I"); . * . . . } all primitive types * (VM_Field) VM.getMember("[J", "length", "I"); ' * (VM_Field) VM.getMember("[Ljava/lang/Object;", "length", "I"); * (VM_Field) VM.getMember("Ljava/lang/Object;", "TIB", "[I"); */ /** Enumeration of Access type */ public static final int FIELD_ACCESS = 0; /** Enumeration of Access type */ public static final int ARRAY_ACCESS = 1; /** Enumeration of Access type */ public static final int JTOC_ACCESS = 2; /** Enumeration of Access type */ public static final int SPILL_ACCESS = 3; /** Enumeration of Access type */ public static final int ALENGTH_ACCESS = 4; /** Enumeration of Access type */ public static final int METHOD_ACCESS = 5; /** * The type of this location. */ int type; /** * Field that corresponds to this location; * null if this is not a field access. */ VM_FieldReference fieldRef; /** * Method operand that corresponds to this location; * null if this is not a method access. */ OPT_MethodOperand methOp; /** * Array element type that corresponds to the type of the array that contains * this location; null if this is not an array access. */ VM_TypeReference arrayElementType; /** * JTOC index that corresponds to this location. * -1 if this is not a JTOC access. */ Offset JTOCoffset = Offset.max(); /** * Spill offset that corresponds to this location. * -1 if this is not a spill access. */ int spillOffset = -1; /** * Reference number. Set by alias analysis. * Used to distinguish same-type accesses. */ int refNumber; /** * Constructs a new location operand with the given field. * @param loc location */ public OPT_LocationOperand(VM_FieldReference loc) { type = FIELD_ACCESS; fieldRef = loc; } /** * Constructs a new location operand with the given field * @param loc location */ public OPT_LocationOperand(VM_Field loc) { type = FIELD_ACCESS; fieldRef = loc.getMemberRef().asFieldReference(); } /** * Constructs a new location operand with the given method * * @param m Method operand that corresponds to this location */ public OPT_LocationOperand(OPT_MethodOperand m) { type = METHOD_ACCESS; methOp = m; } /** * Constructs a new location operand with the given array element type. * * @param t Array element type */ public OPT_LocationOperand(VM_TypeReference t) { type = ARRAY_ACCESS; arrayElementType = t; } /** * Constructs a new location operand with the given JTOC offset */ public OPT_LocationOperand(Offset jtocOffset) { type = JTOC_ACCESS; JTOCoffset = jtocOffset; } /** * Constructs a new location operand with the given spill offset. */ public OPT_LocationOperand(int index) { if (VM.VerifyAssertions) VM._assert(index <= 0); type = SPILL_ACCESS; spillOffset = index; } /** * Constructs a new location operand for array length access. */ public OPT_LocationOperand() { type = ALENGTH_ACCESS; } /** * Return the {@link VM_TypeReference} of the value represented by the operand. * * @return this method shouldn't be called and will throw an {@link * OPT_OptimizingCompilerException} */ public VM_TypeReference getType() { throw new OPT_OptimizingCompilerException("Getting the type for this operand has no defined meaning"); } public OPT_LocationOperand asFieldAccess() { return this; } public OPT_LocationOperand asArrayAccess() { return this; } public OPT_LocationOperand asJTOCAccess() { return this; } public OPT_LocationOperand asSpillAccess() { return this; } public OPT_LocationOperand asALengthAccess() { return this; } public OPT_LocationOperand asMethodAccess() { return this; } public VM_FieldReference getFieldRef() { return fieldRef; } public VM_TypeReference getElementType() { return arrayElementType; } //public final int getIndex() { return JTOCoffset; } public Offset getJTOCoffset() { return JTOCoffset; } public int getOffset() { return spillOffset; } public boolean isFieldAccess() { return type == FIELD_ACCESS; } public boolean isArrayAccess() { return type == ARRAY_ACCESS; } public boolean isJTOCAccess() { return type == JTOC_ACCESS; } public boolean isSpillAccess() { return type == SPILL_ACCESS; } public boolean isALengthAccess() { return type == ALENGTH_ACCESS; } public boolean isMethodAccess() { return type == METHOD_ACCESS; } /** * Is the accessed location possibly volatile? */ public boolean mayBeVolatile() { if (!isFieldAccess()) return false; VM_Field f = fieldRef.peekResolvedField(false); return f == null || f.isVolatile(); } /** * Return a new operand that is semantically equivalent to <code>this</code>. * * @return a copy of <code>this</code> */ public OPT_Operand copy() { OPT_LocationOperand o = null; switch (type) { case FIELD_ACCESS: o = new OPT_LocationOperand(fieldRef); break; case ARRAY_ACCESS: o = new OPT_LocationOperand(arrayElementType); break; case JTOC_ACCESS: o = new OPT_LocationOperand(JTOCoffset); break; case SPILL_ACCESS: o = new OPT_LocationOperand(spillOffset); break; case ALENGTH_ACCESS: o = new OPT_LocationOperand(); break; case METHOD_ACCESS: o = new OPT_LocationOperand(methOp); break; default: o = new OPT_LocationOperand(); break; } return o; } // NOTE: not checking for (t1==null xor t2==null) for efficiency private static boolean arrayMayBeAliased(VM_TypeReference t1, VM_TypeReference t2) { return ((t1 == t2) || (OPT_ClassLoaderProxy.includesType(t1, t2) != NO) || (OPT_ClassLoaderProxy.includesType(t2, t1) != NO)); } /** * Returns true if operands op1 and op2 may be aliased. * * @param op1 the first operand * @param op2 the second operand * @return <code>true</code> if the operands might be aliased or * <code>false</code> if they are definitely not aliased */ public static boolean mayBeAliased(OPT_LocationOperand op1, OPT_LocationOperand op2) { if (op1 == null || op2 == null) return true; // be conservative if (op1.type != op2.type) return false; if (op1.fieldRef != null) { return !op1.fieldRef.definitelyDifferent(op2.fieldRef); } else { return arrayMayBeAliased(op1.arrayElementType, op2.arrayElementType) && (op1.JTOCoffset.EQ(op2.JTOCoffset)) && (op1.spillOffset == op2.spillOffset); } } /** * Are two operands semantically equivalent? * * @param op other operand * @return <code>true</code> if <code>this</code> and <code>op</code> * are semantically equivalent or <code>false</code> * if they are not. */ public boolean similar(OPT_Operand op) { return (op instanceof OPT_LocationOperand) && mayBeAliased(this, (OPT_LocationOperand) op); } /** * Returns the string representation of this operand. * * @return a string representation of this operand. */ public String toString() { if (methOp != null) return methOp.toString(); switch (type) { case METHOD_ACCESS: return "<mem loc: methOp is null!>"; case FIELD_ACCESS: return "<mem loc: " + fieldRef.getType().getName() + "." + fieldRef.getName() + ">"; case ARRAY_ACCESS: return "<mem loc: array " + arrayElementType + "[]>"; case JTOC_ACCESS: return "<mem loc: JTOC @" + VM.addressAsHexString(JTOCoffset.toWord().toAddress()) + ">"; case SPILL_ACCESS: return "<mem loc: spill FP " + spillOffset + ">"; case ALENGTH_ACCESS: return "<mem loc: array length>"; } return "<mem loc: no aliases>"; } }