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 * 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; 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 the {@link TypeReference} of the value represented by the operand.
156 *
157 * @return this method shouldn't be called and will throw an {@link
158 * OptimizingCompilerException}
159 */
160 public TypeReference getType() {
161 throw new OptimizingCompilerException("Getting the type for this operand has no defined meaning");
162 }
163
164 public LocationOperand asFieldAccess() { return this; }
165
166 public LocationOperand asArrayAccess() { return this; }
167
168 public LocationOperand asJTOCAccess() { return this; }
169
170 public LocationOperand asSpillAccess() { return this; }
171
172 public LocationOperand asALengthAccess() { return this; }
173
174 public LocationOperand asMethodAccess() { return this; }
175
176 public FieldReference getFieldRef() { return fieldRef; }
177
178 public TypeReference getElementType() { return arrayElementType; }
179
180 //public final int getIndex() { return JTOCoffset; }
181 public Offset getJTOCoffset() { return JTOCoffset; }
182
183 public int getOffset() { return spillOffset; }
184
185 public boolean isFieldAccess() { return type == FIELD_ACCESS; }
186
187 public boolean isArrayAccess() { return type == ARRAY_ACCESS; }
188
189 public boolean isJTOCAccess() { return type == JTOC_ACCESS; }
190
191 public boolean isSpillAccess() { return type == SPILL_ACCESS; }
192
193 public boolean isALengthAccess() { return type == ALENGTH_ACCESS; }
194
195 public boolean isMethodAccess() { return type == METHOD_ACCESS; }
196
197 /**
198 * Is the accessed location possibly volatile?
199 */
200 public boolean mayBeVolatile() {
201 if (!isFieldAccess()) return false;
202 RVMField f = fieldRef.peekResolvedField();
203 return f == null || f.isVolatile();
204 }
205
206 /**
207 * Return a new operand that is semantically equivalent to <code>this</code>.
208 *
209 * @return a copy of <code>this</code>
210 */
211 public Operand copy() {
212 LocationOperand o = null;
213 switch (type) {
214 case FIELD_ACCESS:
215 o = new LocationOperand(fieldRef);
216 break;
217 case ARRAY_ACCESS:
218 o = new LocationOperand(arrayElementType);
219 break;
220 case JTOC_ACCESS:
221 o = new LocationOperand(JTOCoffset);
222 break;
223 case SPILL_ACCESS:
224 o = new LocationOperand(spillOffset);
225 break;
226 case ALENGTH_ACCESS:
227 o = new LocationOperand();
228 break;
229 case METHOD_ACCESS:
230 o = new LocationOperand(methOp);
231 break;
232 default:
233 o = new LocationOperand();
234 break;
235 }
236 return o;
237 }
238
239 // NOTE: not checking for (t1==null xor t2==null) for efficiency
240 private static boolean arrayMayBeAliased(TypeReference t1, TypeReference t2) {
241 return ((t1 == t2) ||
242 (ClassLoaderProxy.includesType(t1, t2) != NO) ||
243 (ClassLoaderProxy.includesType(t2, t1) != NO));
244 }
245
246 /**
247 * Returns true if operands op1 and op2 may be aliased.
248 *
249 * @param op1 the first operand
250 * @param op2 the second operand
251 * @return <code>true</code> if the operands might be aliased or
252 * <code>false</code> if they are definitely not aliased
253 */
254 public static boolean mayBeAliased(LocationOperand op1, LocationOperand op2) {
255 if (op1 == null || op2 == null) return true; // be conservative
256 if (op1.type != op2.type) return false;
257 if (op1.fieldRef != null) {
258 return !op1.fieldRef.definitelyDifferent(op2.fieldRef);
259 } else {
260 return arrayMayBeAliased(op1.arrayElementType, op2.arrayElementType) &&
261 (op1.JTOCoffset.EQ(op2.JTOCoffset)) &&
262 (op1.spillOffset == op2.spillOffset);
263 }
264 }
265
266 /**
267 * Are two operands semantically equivalent?
268 *
269 * @param op other operand
270 * @return <code>true</code> if <code>this</code> and <code>op</code>
271 * are semantically equivalent or <code>false</code>
272 * if they are not.
273 */
274 public boolean similar(Operand op) {
275 return (op instanceof LocationOperand) && mayBeAliased(this, (LocationOperand) op);
276 }
277
278 /**
279 * Returns the string representation of this operand.
280 *
281 * @return a string representation of this operand.
282 */
283 public String toString() {
284 if (methOp != null) return methOp.toString();
285 switch (type) {
286 case METHOD_ACCESS:
287 return "<mem loc: methOp is null!>";
288 case FIELD_ACCESS:
289 return "<mem loc: " + fieldRef.getType().getName() + "." + fieldRef.getName() + ">";
290 case ARRAY_ACCESS:
291 return "<mem loc: array " + arrayElementType + "[]>";
292 case JTOC_ACCESS:
293 return "<mem loc: JTOC @" + VM.addressAsHexString(JTOCoffset.toWord().toAddress()) + ">";
294 case SPILL_ACCESS:
295 return "<mem loc: spill FP " + spillOffset + ">";
296 case ALENGTH_ACCESS:
297 return "<mem loc: array length>";
298 }
299 return "<mem loc: no aliases>";
300 }
301 }