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.ir.operand; 014 015 import org.jikesrvm.VM; 016 import org.jikesrvm.classloader.RVMField; 017 import org.jikesrvm.classloader.FieldReference; 018 import org.jikesrvm.classloader.TypeReference; 019 import org.jikesrvm.compilers.opt.ClassLoaderProxy; 020 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 021 import org.vmmagic.unboxed.Offset; 022 023 /** 024 * Represents a location in memory. Used to keep track of memory aliasing. 025 * 026 * @see Operand 027 */ 028 public final class LocationOperand extends Operand implements org.jikesrvm.compilers.opt.driver.OptConstants { 029 030 /* 031 * TODO: Now that we don't pay a large penalty for dynamic type checks 032 * of non-final classes, redesign this mess to have separate subclasses 033 * of location operands for each type of memory access. 034 * In the process, also switch to using synthetic Fields 035 * for the various pieces of the object header 036 * (something like the following might work): 037 * (RVMField) VM.getMember("[I", "length", "I"); . 038 * . . . } all primitive types 039 * (RVMField) VM.getMember("[J", "length", "I"); ' 040 * (RVMField) VM.getMember("[Ljava/lang/Object;", "length", "I"); 041 * (RVMField) VM.getMember("Ljava/lang/Object;", "TIB", "[I"); 042 */ 043 044 /** Enumeration of Access type */ 045 public static final int FIELD_ACCESS = 0; 046 /** Enumeration of Access type */ 047 public static final int ARRAY_ACCESS = 1; 048 /** Enumeration of Access type */ 049 public static final int JTOC_ACCESS = 2; 050 /** Enumeration of Access type */ 051 public static final int SPILL_ACCESS = 3; 052 /** Enumeration of Access type */ 053 public static final int ALENGTH_ACCESS = 4; 054 /** Enumeration of Access type */ 055 public static final int METHOD_ACCESS = 5; 056 057 /** 058 * The type of this location. 059 */ 060 int type; 061 062 /** 063 * Field that corresponds to this location; 064 * null if this is not a field access. 065 */ 066 FieldReference fieldRef; 067 068 /** 069 * Method operand that corresponds to this location; 070 * {@code null} if this is not a method access. 071 */ 072 MethodOperand methOp; 073 074 /** 075 * Array element type that corresponds to the type of the array that contains 076 * this location; {@code null} if this is not an array access. 077 */ 078 TypeReference arrayElementType; 079 080 /** 081 * JTOC index that corresponds to this location. 082 * -1 if this is not a JTOC access. 083 */ 084 Offset JTOCoffset = Offset.max(); 085 086 /** 087 * Spill offset that corresponds to this location. 088 * -1 if this is not a spill access. 089 */ 090 int spillOffset = -1; 091 092 /** 093 * Constructs a new location operand with the given field. 094 * @param loc location 095 */ 096 public LocationOperand(FieldReference loc) { 097 type = FIELD_ACCESS; 098 fieldRef = loc; 099 } 100 101 /** 102 * Constructs a new location operand with the given field 103 * @param loc location 104 */ 105 public LocationOperand(RVMField loc) { 106 type = FIELD_ACCESS; 107 fieldRef = loc.getMemberRef().asFieldReference(); 108 } 109 110 /** 111 * Constructs a new location operand with the given method 112 * 113 * @param m Method operand that corresponds to this location 114 */ 115 public LocationOperand(MethodOperand m) { 116 type = METHOD_ACCESS; 117 methOp = m; 118 } 119 120 /** 121 * Constructs a new location operand with the given array element type. 122 * 123 * @param t Array element type 124 */ 125 public LocationOperand(TypeReference t) { 126 type = ARRAY_ACCESS; 127 arrayElementType = t; 128 } 129 130 /** 131 * Constructs a new location operand with the given JTOC offset 132 */ 133 public LocationOperand(Offset jtocOffset) { 134 type = JTOC_ACCESS; 135 JTOCoffset = jtocOffset; 136 } 137 138 /** 139 * Constructs a new location operand with the given spill offset. 140 */ 141 public LocationOperand(int index) { 142 if (VM.VerifyAssertions) VM._assert(index <= 0); 143 type = SPILL_ACCESS; 144 spillOffset = index; 145 } 146 147 /** 148 * Constructs a new location operand for array length access. 149 */ 150 public LocationOperand() { 151 type = ALENGTH_ACCESS; 152 } 153 154 /** 155 * @return this method shouldn't be called and will throw an {@link 156 * OptimizingCompilerException} 157 */ 158 @Override 159 public TypeReference getType() { 160 throw new OptimizingCompilerException("Getting the type for this operand has no defined meaning"); 161 } 162 163 public LocationOperand asFieldAccess() { return this; } 164 165 public LocationOperand asArrayAccess() { return this; } 166 167 public LocationOperand asJTOCAccess() { return this; } 168 169 public LocationOperand asSpillAccess() { return this; } 170 171 public LocationOperand asALengthAccess() { return this; } 172 173 public LocationOperand asMethodAccess() { return this; } 174 175 public FieldReference getFieldRef() { return fieldRef; } 176 177 public TypeReference getElementType() { return arrayElementType; } 178 179 //public final int getIndex() { return JTOCoffset; } 180 public Offset getJTOCoffset() { return JTOCoffset; } 181 182 public int getOffset() { return spillOffset; } 183 184 public boolean isFieldAccess() { return type == FIELD_ACCESS; } 185 186 public boolean isArrayAccess() { return type == ARRAY_ACCESS; } 187 188 public boolean isJTOCAccess() { return type == JTOC_ACCESS; } 189 190 public boolean isSpillAccess() { return type == SPILL_ACCESS; } 191 192 public boolean isALengthAccess() { return type == ALENGTH_ACCESS; } 193 194 public boolean isMethodAccess() { return type == METHOD_ACCESS; } 195 196 /** 197 * Is the accessed location possibly volatile? 198 */ 199 public boolean mayBeVolatile() { 200 if (!isFieldAccess()) return false; 201 RVMField f = fieldRef.peekResolvedField(); 202 return f == null || f.isVolatile(); 203 } 204 205 @Override 206 public Operand copy() { 207 LocationOperand o = null; 208 switch (type) { 209 case FIELD_ACCESS: 210 o = new LocationOperand(fieldRef); 211 break; 212 case ARRAY_ACCESS: 213 o = new LocationOperand(arrayElementType); 214 break; 215 case JTOC_ACCESS: 216 o = new LocationOperand(JTOCoffset); 217 break; 218 case SPILL_ACCESS: 219 o = new LocationOperand(spillOffset); 220 break; 221 case ALENGTH_ACCESS: 222 o = new LocationOperand(); 223 break; 224 case METHOD_ACCESS: 225 o = new LocationOperand(methOp); 226 break; 227 default: 228 o = new LocationOperand(); 229 break; 230 } 231 return o; 232 } 233 234 // NOTE: not checking for (t1==null xor t2==null) for efficiency 235 private static boolean arrayMayBeAliased(TypeReference t1, TypeReference t2) { 236 return ((t1 == t2) || 237 (ClassLoaderProxy.includesType(t1, t2) != NO) || 238 (ClassLoaderProxy.includesType(t2, t1) != NO)); 239 } 240 241 /** 242 * Returns true if operands op1 and op2 may be aliased. 243 * 244 * @param op1 the first operand 245 * @param op2 the second operand 246 * @return <code>true</code> if the operands might be aliased or 247 * <code>false</code> if they are definitely not aliased 248 */ 249 public static boolean mayBeAliased(LocationOperand op1, LocationOperand op2) { 250 if (op1 == null || op2 == null) return true; // be conservative 251 if (op1.type != op2.type) return false; 252 if (op1.fieldRef != null) { 253 return !op1.fieldRef.definitelyDifferent(op2.fieldRef); 254 } else { 255 return arrayMayBeAliased(op1.arrayElementType, op2.arrayElementType) && 256 (op1.JTOCoffset.EQ(op2.JTOCoffset)) && 257 (op1.spillOffset == op2.spillOffset); 258 } 259 } 260 261 @Override 262 public boolean similar(Operand op) { 263 return (op instanceof LocationOperand) && mayBeAliased(this, (LocationOperand) op); 264 } 265 266 /** 267 * Returns the string representation of this operand. 268 * 269 * @return a string representation of this operand. 270 */ 271 @Override 272 public String toString() { 273 if (methOp != null) return methOp.toString(); 274 switch (type) { 275 case METHOD_ACCESS: 276 return "<mem loc: methOp is null!>"; 277 case FIELD_ACCESS: 278 return "<mem loc: " + fieldRef.getType().getName() + "." + fieldRef.getName() + ">"; 279 case ARRAY_ACCESS: 280 return "<mem loc: array " + arrayElementType + "[]>"; 281 case JTOC_ACCESS: 282 return "<mem loc: JTOC @" + VM.addressAsHexString(JTOCoffset.toWord().toAddress()) + ">"; 283 case SPILL_ACCESS: 284 return "<mem loc: spill FP " + spillOffset + ">"; 285 case ALENGTH_ACCESS: 286 return "<mem loc: array length>"; 287 } 288 return "<mem loc: no aliases>"; 289 } 290 }