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    }