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}