0
|
1 /*
|
|
2 * Copyright 2000-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any 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 Where: [15]
|
|
43 Type: [14..12]
|
|
44 Offset: [11..0]
|
|
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_INT_IN_LONG = db.lookupIntConstant("Location::int_in_long").intValue();
|
|
73 TYPE_LNG = db.lookupIntConstant("Location::lng").intValue();
|
|
74 TYPE_FLOAT_IN_DBL = db.lookupIntConstant("Location::float_in_dbl").intValue();
|
|
75 TYPE_DBL = db.lookupIntConstant("Location::dbl").intValue();
|
|
76 TYPE_ADDR = db.lookupIntConstant("Location::addr").intValue();
|
|
77 TYPE_INVALID = db.lookupIntConstant("Location::invalid").intValue();
|
|
78
|
|
79 // Location::Where constants
|
|
80 WHERE_ON_STACK = db.lookupIntConstant("Location::on_stack").intValue();
|
|
81 WHERE_IN_REGISTER = db.lookupIntConstant("Location::in_register").intValue();
|
|
82 }
|
|
83
|
|
84 private int value;
|
|
85
|
|
86 // type safe enum for "Where"
|
|
87 public static class Where {
|
|
88 public static final Where ON_STACK = new Where("on_stack");
|
|
89 public static final Where IN_REGISTER = new Where("in_register");
|
|
90
|
|
91 private Where(String value) {
|
|
92 this.value = value;
|
|
93 }
|
|
94
|
|
95 public String toString() {
|
|
96 return value;
|
|
97 }
|
|
98
|
|
99 private String value;
|
|
100
|
|
101 public int getValue() {
|
|
102 if (this == ON_STACK) {
|
|
103 return WHERE_ON_STACK;
|
|
104 } else if (this == IN_REGISTER) {
|
|
105 return WHERE_IN_REGISTER;
|
|
106 } else {
|
|
107 throw new RuntimeException("should not reach here");
|
|
108 }
|
|
109 }
|
|
110 }
|
|
111
|
|
112 // type safe enum for "Type"
|
|
113 public static class Type {
|
|
114 /** Ints, floats, double halves */
|
|
115 public static final Type NORMAL = new Type("normal");
|
|
116 /** Oop (please GC me!) */
|
|
117 public static final Type OOP = new Type("oop");
|
|
118 /** Long held in one register */
|
|
119 public static final Type INT_IN_LONG = new Type("int_in_long");
|
|
120 /** Long held in one register */
|
|
121 public static final Type LNG = new Type("lng");
|
|
122 /** Float held in double register */
|
|
123 public static final Type FLOAT_IN_DBL = new Type("float_in_dbl");
|
|
124 /** Double held in one register */
|
|
125 public static final Type DBL = new Type("dbl");
|
|
126 /** JSR return address */
|
|
127 public static final Type ADDR = new Type("addr");
|
|
128 /** Invalid location */
|
|
129 public static final Type INVALID = new Type("invalid");
|
|
130
|
|
131 private Type(String value) {
|
|
132 this.value = value;
|
|
133 }
|
|
134 private String value;
|
|
135
|
|
136 public String toString() {
|
|
137 return value;
|
|
138 }
|
|
139
|
|
140 public int getValue() {
|
|
141 if (this == NORMAL) {
|
|
142 return TYPE_NORMAL;
|
|
143 } else if (this == OOP) {
|
|
144 return TYPE_OOP;
|
|
145 } else if (this == INT_IN_LONG) {
|
|
146 return TYPE_INT_IN_LONG;
|
|
147 } else if (this == LNG) {
|
|
148 return TYPE_LNG;
|
|
149 } else if (this == FLOAT_IN_DBL) {
|
|
150 return TYPE_FLOAT_IN_DBL;
|
|
151 } else if (this == DBL) {
|
|
152 return TYPE_DBL;
|
|
153 } else if (this == ADDR) {
|
|
154 return TYPE_ADDR;
|
|
155 } else if (this == INVALID) {
|
|
156 return TYPE_INVALID;
|
|
157 } else {
|
|
158 throw new RuntimeException("should not reach here");
|
|
159 }
|
|
160 }
|
|
161 }
|
|
162
|
|
163 private static int OFFSET_MASK;
|
|
164 private static int OFFSET_SHIFT;
|
|
165 private static int TYPE_MASK;
|
|
166 private static int TYPE_SHIFT;
|
|
167 private static int WHERE_MASK;
|
|
168 private static int WHERE_SHIFT;
|
|
169
|
|
170 // constants in Type enum
|
|
171 private static int TYPE_NORMAL;
|
|
172 private static int TYPE_OOP;
|
|
173 private static int TYPE_INT_IN_LONG;
|
|
174 private static int TYPE_LNG;
|
|
175 private static int TYPE_FLOAT_IN_DBL;
|
|
176 private static int TYPE_DBL;
|
|
177 private static int TYPE_ADDR;
|
|
178 private static int TYPE_INVALID;
|
|
179
|
|
180 // constants in Where enum
|
|
181 private static int WHERE_ON_STACK;
|
|
182 private static int WHERE_IN_REGISTER;
|
|
183
|
|
184 /** Create a bit-packed Location */
|
|
185 Location(Where where, Type type, int offset) {
|
|
186 setWhere(where);
|
|
187 setType(type);
|
|
188 setOffset(offset & 0x0000FFFF);
|
|
189 }
|
|
190
|
|
191 public Where getWhere() {
|
|
192 int where = (value & WHERE_MASK) >> WHERE_SHIFT;
|
|
193 if (where == WHERE_ON_STACK) {
|
|
194 return Where.ON_STACK;
|
|
195 } else if (where == WHERE_IN_REGISTER) {
|
|
196 return Where.IN_REGISTER;
|
|
197 } else {
|
|
198 throw new RuntimeException("should not reach here");
|
|
199 }
|
|
200 }
|
|
201
|
|
202 public Type getType() {
|
|
203 int type = (value & TYPE_MASK) >> TYPE_SHIFT;
|
|
204 if (type == TYPE_NORMAL) {
|
|
205 return Type.NORMAL;
|
|
206 } else if (type == TYPE_OOP) {
|
|
207 return Type.OOP;
|
|
208 } else if (type == TYPE_INT_IN_LONG) {
|
|
209 return Type.INT_IN_LONG;
|
|
210 } else if (type == TYPE_LNG) {
|
|
211 return Type.LNG;
|
|
212 } else if (type == TYPE_FLOAT_IN_DBL) {
|
|
213 return Type.FLOAT_IN_DBL;
|
|
214 } else if (type == TYPE_DBL) {
|
|
215 return Type.DBL;
|
|
216 } else if (type == TYPE_ADDR) {
|
|
217 return Type.ADDR;
|
|
218 } else if (type == TYPE_INVALID) {
|
|
219 return Type.INVALID;
|
|
220 } else {
|
|
221 throw new RuntimeException("should not reach here");
|
|
222 }
|
|
223 }
|
|
224
|
|
225 public short getOffset() {
|
|
226 return (short) ((value & OFFSET_MASK) >> OFFSET_SHIFT);
|
|
227 }
|
|
228
|
|
229 public boolean isRegister() {
|
|
230 return getWhere() == Where.IN_REGISTER;
|
|
231 }
|
|
232
|
|
233 public boolean isStack() {
|
|
234 return getWhere() == Where.ON_STACK;
|
|
235 }
|
|
236
|
|
237 public boolean holdsOop() {
|
|
238 return getType() == Type.OOP;
|
|
239 }
|
|
240
|
|
241 public boolean holdsInt() {
|
|
242 return getType() == Type.INT_IN_LONG;
|
|
243 }
|
|
244
|
|
245 public boolean holdsLong() {
|
|
246 return getType() == Type.LNG;
|
|
247 }
|
|
248
|
|
249 public boolean holdsFloat() {
|
|
250 return getType() == Type.FLOAT_IN_DBL;
|
|
251 }
|
|
252
|
|
253 public boolean holdsDouble() {
|
|
254 return getType() == Type.DBL;
|
|
255 }
|
|
256
|
|
257 public boolean holdsAddr() {
|
|
258 return getType() == Type.ADDR;
|
|
259 }
|
|
260
|
|
261 public boolean isIllegal() {
|
|
262 return getType() == Type.INVALID;
|
|
263 }
|
|
264
|
|
265 public int getStackOffset() {
|
|
266 if (Assert.ASSERTS_ENABLED) {
|
|
267 Assert.that(getWhere() == Where.ON_STACK, "wrong Where");
|
|
268 }
|
|
269 return getOffset() << VM.getVM().getLogAddressSize();
|
|
270 }
|
|
271
|
|
272 public int getRegisterNumber() {
|
|
273 if (Assert.ASSERTS_ENABLED) {
|
|
274 Assert.that(getWhere() == Where.IN_REGISTER, "wrong Where");
|
|
275 }
|
|
276 return getOffset();
|
|
277 }
|
|
278
|
|
279 public void print() {
|
|
280 printOn(System.out);
|
|
281 }
|
|
282
|
|
283 public void printOn(PrintStream tty) {
|
|
284 tty.print("Value " + value + ", ");
|
|
285 if (isIllegal()) {
|
|
286 tty.print("Illegal");
|
|
287 } else {
|
|
288 Where w = getWhere();
|
|
289 if (w == Where.ON_STACK) {
|
|
290 tty.print("stack[" + getStackOffset() + "]");
|
|
291 } else if (w == Where.IN_REGISTER) {
|
|
292 tty.print("reg " + getRegisterNumber());
|
|
293 }
|
|
294
|
|
295 Type type = getType();
|
|
296 if (type == Type.NORMAL) {
|
|
297 } else if (type == Type.OOP) {
|
|
298 tty.print(",oop");
|
|
299 } else if (type == Type.INT_IN_LONG) {
|
|
300 tty.print(",int");
|
|
301 } else if (type == Type.LNG) {
|
|
302 tty.print(",long");
|
|
303 } else if (type == Type.FLOAT_IN_DBL) {
|
|
304 tty.print(",float");
|
|
305 } else if (type == Type.DBL) {
|
|
306 tty.print(",double");
|
|
307 } else if (type == Type.ADDR) {
|
|
308 tty.print(",address");
|
|
309 } else if (type == Type.INVALID) {
|
|
310 tty.print(",invalid");
|
|
311 }
|
|
312 }
|
|
313 }
|
|
314
|
|
315 /** Serialization of debugging information */
|
|
316 public Location(DebugInfoReadStream stream) {
|
|
317 value = (0x0000FFFF & stream.readInt());
|
|
318 }
|
|
319
|
|
320 // FIXME: not yet implementable
|
|
321 // void write_on(DebugInfoWriteStream* stream);
|
|
322
|
|
323
|
|
324 //--------------------------------------------------------------------------------
|
|
325 // Internals only below this point
|
|
326 //
|
|
327
|
|
328 private void setWhere(Where where) {
|
|
329 value |= (where.getValue() << WHERE_SHIFT);
|
|
330 }
|
|
331
|
|
332 private void setType(Type type) {
|
|
333 value |= (type.getValue() << TYPE_SHIFT);
|
|
334 }
|
|
335
|
|
336 private void setOffset(int offset) {
|
|
337 value |= (offset << OFFSET_SHIFT);
|
|
338 }
|
|
339 }
|