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