View Javadoc
1   /*
2    * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   *
23   */
24  
25  package sun.jvm.hotspot.code;
26  
27  import java.io.*;
28  import java.util.*;
29  
30  import sun.jvm.hotspot.runtime.*;
31  import sun.jvm.hotspot.types.*;
32  import sun.jvm.hotspot.utilities.*;
33  
34  /** <P> A Location describes a concrete machine variable location
35      (such as integer or floating point register or a stack-held
36      variable). Used when generating debug-information for
37      nmethods. </P>
38  
39      <P> Encoding: </P>
40      <PRE>
41      bits:
42      Type:   [3..0]
43      Where:  [4]
44      Offset: [31..5]
45      </PRE>
46  */
47  
48  public class Location {
49    static {
50      VM.registerVMInitializedObserver(new Observer() {
51          public void update(Observable o, Object data) {
52            initialize(VM.getVM().getTypeDataBase());
53          }
54        });
55    }
56  
57    private static void initialize(TypeDataBase db) {
58      if (Assert.ASSERTS_ENABLED) {
59        Assert.that(!VM.getVM().isCore(), "Debug info not used in core build");
60      }
61  
62      OFFSET_MASK  = db.lookupIntConstant("Location::OFFSET_MASK").intValue();
63      OFFSET_SHIFT = db.lookupIntConstant("Location::OFFSET_SHIFT").intValue();
64      TYPE_MASK    = db.lookupIntConstant("Location::TYPE_MASK").intValue();
65      TYPE_SHIFT   = db.lookupIntConstant("Location::TYPE_SHIFT").intValue();
66      WHERE_MASK   = db.lookupIntConstant("Location::WHERE_MASK").intValue();
67      WHERE_SHIFT  = db.lookupIntConstant("Location::WHERE_SHIFT").intValue();
68  
69      // Location::Type constants
70      TYPE_NORMAL = db.lookupIntConstant("Location::normal").intValue();
71      TYPE_OOP = db.lookupIntConstant("Location::oop").intValue();
72      TYPE_NARROWOOP = db.lookupIntConstant("Location::narrowoop").intValue();
73      TYPE_INT_IN_LONG = db.lookupIntConstant("Location::int_in_long").intValue();
74      TYPE_LNG = db.lookupIntConstant("Location::lng").intValue();
75      TYPE_FLOAT_IN_DBL = db.lookupIntConstant("Location::float_in_dbl").intValue();
76      TYPE_DBL = db.lookupIntConstant("Location::dbl").intValue();
77      TYPE_ADDR = db.lookupIntConstant("Location::addr").intValue();
78      TYPE_INVALID = db.lookupIntConstant("Location::invalid").intValue();
79  
80      // Location::Where constants
81      WHERE_ON_STACK = db.lookupIntConstant("Location::on_stack").intValue();
82      WHERE_IN_REGISTER = db.lookupIntConstant("Location::in_register").intValue();
83    }
84  
85    private int value;
86  
87    // type safe enum for "Where"
88    public static class Where {
89      public static final Where ON_STACK    = new Where("on_stack");
90      public static final Where IN_REGISTER = new Where("in_register");
91  
92      private Where(String value) {
93        this.value = value;
94      }
95  
96      public String toString() {
97        return value;
98      }
99  
100     private String value;
101 
102     public int getValue() {
103       if (this == ON_STACK) {
104          return WHERE_ON_STACK;
105       } else if (this == IN_REGISTER) {
106          return WHERE_IN_REGISTER;
107       } else {
108          throw new RuntimeException("should not reach here");
109       }
110     }
111   }
112 
113   // type safe enum for "Type"
114   public static class Type {
115     /** Ints, floats, double halves */
116     public static final Type NORMAL       = new Type("normal");
117     /** Oop (please GC me!) */
118     public static final Type OOP          = new Type("oop");
119     /** NarrowOop (please GC me!) */
120     public static final Type NARROWOOP    = new Type("narrowoop");
121     /** Long held in one register */
122     public static final Type INT_IN_LONG  = new Type("int_in_long");
123     /** Long held in one register */
124     public static final Type LNG          = new Type("lng");
125     /** Float held in double register */
126     public static final Type FLOAT_IN_DBL = new Type("float_in_dbl");
127     /** Double held in one register */
128     public static final Type DBL          = new Type("dbl");
129     /** JSR return address */
130     public static final Type ADDR         = new Type("addr");
131     /** Invalid location */
132     public static final Type INVALID      = new Type("invalid");
133 
134     private Type(String value) {
135       this.value = value;
136     }
137     private String value;
138 
139     public String toString() {
140       return value;
141     }
142 
143     public int getValue() {
144       if (this == NORMAL) {
145         return TYPE_NORMAL;
146       } else if (this == OOP) {
147         return TYPE_OOP;
148       } else if (this == NARROWOOP) {
149         return TYPE_NARROWOOP;
150       } else if (this == INT_IN_LONG) {
151         return TYPE_INT_IN_LONG;
152       } else if (this == LNG) {
153         return TYPE_LNG;
154       } else if (this == FLOAT_IN_DBL) {
155         return TYPE_FLOAT_IN_DBL;
156       } else if (this == DBL) {
157         return TYPE_DBL;
158       } else if (this == ADDR) {
159         return TYPE_ADDR;
160       } else if (this == INVALID) {
161         return TYPE_INVALID;
162       } else {
163         throw new RuntimeException("should not reach here");
164       }
165     }
166   }
167 
168   private static int OFFSET_MASK;
169   private static int OFFSET_SHIFT;
170   private static int TYPE_MASK;
171   private static int TYPE_SHIFT;
172   private static int WHERE_MASK;
173   private static int WHERE_SHIFT;
174 
175   // constants in Type enum
176   private static int TYPE_NORMAL;
177   private static int TYPE_OOP;
178   private static int TYPE_NARROWOOP;
179   private static int TYPE_INT_IN_LONG;
180   private static int TYPE_LNG;
181   private static int TYPE_FLOAT_IN_DBL;
182   private static int TYPE_DBL;
183   private static int TYPE_ADDR;
184   private static int TYPE_INVALID;
185 
186   // constants in Where enum
187   private static int WHERE_ON_STACK;
188   private static int WHERE_IN_REGISTER;
189 
190   /** Create a bit-packed Location */
191   Location(Where where, Type type, int offset) {
192     setWhere(where);
193     setType(type);
194     setOffset(offset);
195   }
196 
197   public Where getWhere() {
198     int where = (value & WHERE_MASK) >> WHERE_SHIFT;
199     if (where == WHERE_ON_STACK) {
200        return Where.ON_STACK;
201     } else if (where == WHERE_IN_REGISTER) {
202        return Where.IN_REGISTER;
203     } else {
204        throw new RuntimeException("should not reach here");
205     }
206   }
207 
208   public Type getType() {
209     int type = (value & TYPE_MASK) >> TYPE_SHIFT;
210     if (type == TYPE_NORMAL) {
211        return Type.NORMAL;
212     } else if (type == TYPE_OOP) {
213        return Type.OOP;
214     } else if (type == TYPE_NARROWOOP) {
215        return Type.NARROWOOP;
216     } else if (type == TYPE_INT_IN_LONG) {
217        return Type.INT_IN_LONG;
218     } else if (type == TYPE_LNG) {
219        return Type.LNG;
220     } else if (type == TYPE_FLOAT_IN_DBL) {
221        return Type.FLOAT_IN_DBL;
222     } else if (type == TYPE_DBL) {
223        return Type.DBL;
224     } else if (type == TYPE_ADDR) {
225        return Type.ADDR;
226     } else if (type == TYPE_INVALID) {
227        return Type.INVALID;
228     } else {
229        throw new RuntimeException("should not reach here");
230     }
231   }
232 
233   public short getOffset() {
234     return (short) ((value & OFFSET_MASK) >> OFFSET_SHIFT);
235   }
236 
237   public boolean isRegister() {
238     return getWhere() == Where.IN_REGISTER;
239   }
240 
241   public boolean isStack() {
242     return getWhere() == Where.ON_STACK;
243   }
244 
245   public boolean holdsOop() {
246     return getType() == Type.OOP;
247   }
248 
249   public boolean holdsNarrowOop() {
250     return getType() == Type.NARROWOOP;
251   }
252 
253   public boolean holdsInt() {
254     return getType() == Type.INT_IN_LONG;
255   }
256 
257   public boolean holdsLong() {
258     return getType() == Type.LNG;
259   }
260 
261   public boolean holdsFloat() {
262     return getType() == Type.FLOAT_IN_DBL;
263   }
264 
265   public boolean holdsDouble() {
266     return getType() == Type.DBL;
267   }
268 
269   public boolean holdsAddr() {
270     return getType() == Type.ADDR;
271   }
272 
273   public boolean isIllegal() {
274     return getType() == Type.INVALID;
275   }
276 
277   public int getStackOffset() {
278     if (Assert.ASSERTS_ENABLED) {
279       Assert.that(getWhere() == Where.ON_STACK, "wrong Where");
280     }
281     return getOffset() * (int)VM.getVM().getIntSize();
282   }
283 
284   public int getRegisterNumber() {
285     if (Assert.ASSERTS_ENABLED) {
286       Assert.that(getWhere() == Where.IN_REGISTER, "wrong Where");
287     }
288     return getOffset();
289   }
290 
291   public void print() {
292     printOn(System.out);
293   }
294 
295   public void printOn(PrintStream tty) {
296     tty.print("Value " + value + ", ");
297     if (isIllegal()) {
298       tty.print("Illegal");
299     } else {
300       Where w = getWhere();
301       if (w == Where.ON_STACK) {
302         tty.print("stack[" + getStackOffset() + "]");
303       } else if (w == Where.IN_REGISTER) {
304         tty.print("reg " + getRegisterNumber());
305       }
306 
307       Type type = getType();
308       if (type == Type.NORMAL) {
309       } else if (type == Type.OOP) {
310         tty.print(",oop");
311       } else if (type == Type.NARROWOOP) {
312         tty.print(",narrowoop");
313       } else if (type == Type.INT_IN_LONG) {
314         tty.print(",int");
315       } else if (type == Type.LNG) {
316         tty.print(",long");
317       } else if (type == Type.FLOAT_IN_DBL) {
318         tty.print(",float");
319       } else if (type == Type.DBL) {
320         tty.print(",double");
321       } else if (type == Type.ADDR) {
322         tty.print(",address");
323       } else if (type == Type.INVALID) {
324         tty.print(",invalid");
325       }
326     }
327   }
328 
329   /** Serialization of debugging information */
330   public Location(DebugInfoReadStream stream) {
331     value = stream.readInt();
332   }
333 
334   // FIXME: not yet implementable
335   // void write_on(DebugInfoWriteStream* stream);
336 
337 
338   //-----------------------------------------------------------------------------
339   // Internals only below this point
340   //
341 
342   private void setWhere(Where where) {
343     value |= ((where.getValue() << WHERE_SHIFT) & WHERE_MASK);
344   }
345 
346   private void setType(Type type) {
347     value |= ((type.getValue() << TYPE_SHIFT) & TYPE_MASK);
348   }
349 
350   private void setOffset(int offset) {
351     value |= ((offset << OFFSET_SHIFT) & OFFSET_MASK);
352   }
353 }