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.osr;
014
015import static org.jikesrvm.osr.OSRConstants.DOUBLE;
016import static org.jikesrvm.osr.OSRConstants.FLOAT;
017import static org.jikesrvm.osr.OSRConstants.INT;
018import static org.jikesrvm.osr.OSRConstants.LOCAL;
019import static org.jikesrvm.osr.OSRConstants.LONG;
020import static org.jikesrvm.osr.OSRConstants.REF;
021import static org.jikesrvm.osr.OSRConstants.RET_ADDR;
022import static org.jikesrvm.osr.OSRConstants.WORD;
023
024import org.jikesrvm.VM;
025import org.jikesrvm.runtime.Magic;
026import org.jikesrvm.util.Services;
027import org.vmmagic.unboxed.Word;
028
029/**
030 * An instance of VariableElement represents a byte code variable
031 * (local or stack element).  It is used to generate prologue to
032 * recover the runtime state.  It refers to VM architecture.
033 */
034public class VariableElement {
035
036  //////////////////////////////////
037  // instance fields
038  //////////////////////////////////
039
040  /** the kind of this element : LOCAL or STACK */
041  private final boolean kind;
042
043  /**
044   * the number of element, e.g., with kind we
045   * can know it is L0 or S1.
046   */
047  private final char num;
048
049  /** type code, can only be INT, FLOAT, LONG, DOUBLE, RET_ADDR, WORD or REF */
050  private final byte tcode;
051
052  /**
053   * The value of this element.
054   * For type INT, FLOAT, RET_ADDR and WORD (32-bit), the lower 32 bits are valid.
055   * For type LONG and DOUBLE and WORD(64-bit), 64 bits are valid.
056   * For REF type, next field 'ref' is valid.
057   *
058   * For FLOAT, and DOUBLE, use Magic.intBitsAsFloat
059   *                         or Magic.longBitsAsDouble
060   * to convert bits to floating-point value.
061   */
062  private final long value;
063
064  /** for reference type value */
065  private final Object ref;
066
067  //////////////////////////////////
068  // class auxiliary methods
069  /////////////////////////////////
070  static boolean isIBitsType(int tcode) {
071    switch (tcode) {
072      case INT:
073      case FLOAT:
074      case RET_ADDR:
075        return true;
076      case WORD:
077        return VM.BuildFor32Addr;
078      default:
079        return false;
080    }
081  }
082
083  static boolean isLBitsType(int tcode) {
084    switch (tcode) {
085      case LONG:
086      case DOUBLE:
087        return true;
088      case WORD:
089        return VM.BuildFor64Addr;
090      default:
091        return false;
092    }
093  }
094
095  static boolean isRefType(int tcode) {
096    return tcode == REF;
097  }
098
099  static boolean isWordType(int tcode) {
100    return tcode == WORD;
101  }
102
103  //////////////////////////////////////
104  // Initializer
105  /////////////////////////////////////
106
107  /**
108   * Constructor for 32-bit value.
109   *
110   * @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
111   * @param which_num the variable's number
112   * @param type the variable's type code
113   * @param ibits the variable's value
114   */
115  public VariableElement(boolean what_kind, int which_num, byte type, int ibits) {
116    if (VM.VerifyAssertions) {
117      VM._assert(isIBitsType(type));
118      VM._assert(which_num < 0xFFFF);
119    }
120
121    this.kind = what_kind;
122    this.num = (char)which_num;
123    this.tcode = type;
124    this.value = ibits & 0x0FFFFFFFFL;
125    this.ref = null;
126  }
127
128  /**
129   * Constructor for 64-bit value.
130   *
131   * @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
132   * @param which_num the variable's number
133   * @param type the variable's type code
134   * @param lbits the variable's value
135   */
136  public VariableElement(boolean what_kind, int which_num, byte type, long lbits) {
137    if (VM.VerifyAssertions) {
138      VM._assert(isLBitsType(type));
139      VM._assert(which_num < 0xFFFF);
140    }
141
142    this.kind = what_kind;
143    this.num = (char)which_num;
144    this.tcode = type;
145    this.value = lbits;
146    this.ref = null;
147  }
148
149  /**
150   * Constructor for reference type.
151   *
152   * @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
153   * @param which_num the variable's number
154   * @param type the variable's type code
155   * @param ref the reference
156   */
157  public VariableElement(boolean what_kind, int which_num, byte type, Object ref) {
158    if (VM.VerifyAssertions) {
159      VM._assert(isRefType(type));
160      VM._assert(which_num < 0xFFFF);
161    }
162
163    this.kind = what_kind;
164    this.num = (char)which_num;
165    this.tcode = type;
166    this.value = 0;
167    this.ref = ref;
168  }
169
170  /**
171   * Constructor for word type.
172   *
173   * @param what_kind {@link OSRConstants#LOCAL} or {@link OSRConstants#STACK}
174   * @param which_num the variable's number
175   * @param type the variable's type code
176   * @param word the word
177   */
178  public VariableElement(boolean what_kind, int which_num, byte type, Word word) {
179    if (VM.VerifyAssertions) {
180      VM._assert(isWordType(type));
181      VM._assert(which_num < 0xFFFF);
182    }
183
184    this.kind = what_kind;
185    this.num = (char)which_num;
186    this.tcode = type;
187    if (VM.BuildFor32Addr) {
188      this.value = (word.toInt()) & 0x0FFFFFFFFL;
189    } else {
190      this.value = word.toLong();
191    }
192    this.ref = null;
193  }
194
195  ////////////////////////////////
196  // instance method
197  ////////////////////////////////
198
199  /** @return whether this is a local or stack element */
200  boolean isLocal() {
201    return kind == LOCAL;
202  }
203
204  byte getTypeCode() {
205    return tcode;
206  }
207
208  char getNumber() {
209    return num;
210  }
211
212  boolean isRefType() {
213    return (this.tcode == REF);
214  }
215
216  Object getObject() {
217    return ref;
218  }
219
220  boolean isWordType() {
221    return (this.tcode == WORD);
222  }
223
224  Word getWord() {
225    return (VM.BuildFor32Addr) ? Word.fromIntSignExtend((int) value) : Word.fromLong(value);
226  }
227
228  int getIntBits() {
229    return (int) (value & 0x0FFFFFFFF);
230  }
231
232  long getLongBits() {
233    return value;
234  }
235
236  @Override
237  public String toString() {
238    StringBuilder buf = new StringBuilder("(");
239
240    if (kind == LOCAL) {
241      buf.append('L');
242    } else {
243      buf.append('S');
244    }
245    buf.append((int)num);
246    buf.append(",");
247
248    char t = 'V';
249    switch (tcode) {
250      case INT:
251        t = 'I';
252        break;
253      case FLOAT:
254        t = 'F';
255        break;
256      case LONG:
257        t = 'J';
258        break;
259      case DOUBLE:
260        t = 'D';
261        break;
262      case RET_ADDR:
263        t = 'R';
264        break;
265      case REF:
266        t = 'L';
267        break;
268      case WORD:
269        t = 'W';
270        break;
271    }
272
273    buf.append(t);
274    buf.append(",");
275
276    switch (tcode) {
277      case REF:
278        // it is legal to have a null reference.
279        if (ref == null) {
280          buf.append("null");
281        } else {
282          buf.append(Services.addressAsHexString(Magic.objectAsAddress(ref)));
283          buf.append(" ");
284//      buf.append(ref.toString());
285        }
286        break;
287      case WORD:
288        buf.append("0x");
289        if (VM.BuildFor32Addr) {
290          buf.append(Integer.toHexString((int) (value & 0x0FFFFFFFFL)));
291        } else {
292          buf.append(Long.toHexString(value));
293        }
294        buf.append(" ");
295        break;
296      case FLOAT:
297        buf.append(Magic.intBitsAsFloat((int) (value & 0x0FFFFFFFF)));
298        break;
299      case LONG:
300        buf.append(value);
301        break;
302      case DOUBLE:
303        buf.append(Magic.longBitsAsDouble(value));
304        break;
305      default:
306        buf.append((int) (value & 0x0FFFFFFFF));
307        break;
308    }
309
310    buf.append(")");
311
312    return buf.toString();
313  }
314}