0
|
1 /*
|
|
2 * Copyright 2000-2004 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.types.basic;
|
|
26
|
|
27 import java.util.*;
|
|
28 import sun.jvm.hotspot.debugger.*;
|
|
29 import sun.jvm.hotspot.types.*;
|
|
30
|
|
31 /** <P> This is a basic implementation of the TypeDataBase interface.
|
|
32 It allows an external type database builder to add types to be
|
|
33 consumed by a client through the Type interfaces. It has no
|
|
34 knowledge of symbol lookup; for example, the builder is
|
|
35 responsible for providing the addresses of static fields. </P>
|
|
36
|
|
37 <P> Among other things, the database builder is responsible for
|
|
38 providing the Types for the Java primitive types, as well as their
|
|
39 sizes. </P>
|
|
40 */
|
|
41
|
|
42 public class BasicTypeDataBase implements TypeDataBase {
|
|
43 private MachineDescription machDesc;
|
|
44 private VtblAccess vtblAccess;
|
|
45 /** Maps strings to Type objects. This does not contain the primitive types. */
|
|
46 private Map nameToTypeMap = new HashMap();
|
|
47 /** Maps strings to Integers, used for enums, etc. */
|
|
48 private Map nameToIntConstantMap = new HashMap();
|
|
49 /** Maps strings to Longs, used for 32/64-bit constants, etc. */
|
|
50 private Map nameToLongConstantMap = new HashMap();
|
|
51 /** Primitive types. */
|
|
52 private Type jbooleanType;
|
|
53 private Type jbyteType;
|
|
54 private Type jcharType;
|
|
55 private Type jdoubleType;
|
|
56 private Type jfloatType;
|
|
57 private Type jintType;
|
|
58 private Type jlongType;
|
|
59 private Type jshortType;
|
|
60
|
|
61 /** For debugging */
|
|
62 private static final boolean DEBUG;
|
|
63 static {
|
|
64 DEBUG = System.getProperty("sun.jvm.hotspot.types.basic.BasicTypeDataBase.DEBUG") != null;
|
|
65 }
|
|
66
|
|
67 public BasicTypeDataBase(MachineDescription machDesc, VtblAccess vtblAccess) {
|
|
68 this.machDesc = machDesc;
|
|
69 this.vtblAccess = vtblAccess;
|
|
70 }
|
|
71
|
|
72 public Type lookupType(String cTypeName) {
|
|
73 return lookupType(cTypeName, true);
|
|
74 }
|
|
75
|
|
76 public Type lookupType(String cTypeName, boolean throwException) {
|
|
77 Type type = (Type) nameToTypeMap.get(cTypeName);
|
|
78 if (type == null && throwException) {
|
|
79 throw new RuntimeException("No type named \"" + cTypeName + "\" in database");
|
|
80 }
|
|
81 return type;
|
|
82 }
|
|
83
|
|
84 public Integer lookupIntConstant(String constantName) {
|
|
85 return lookupIntConstant(constantName, true);
|
|
86 }
|
|
87
|
|
88 public Integer lookupIntConstant(String constantName, boolean throwException) {
|
|
89 Integer i = (Integer) nameToIntConstantMap.get(constantName);
|
|
90 if (i == null) {
|
|
91 if (throwException) {
|
|
92 throw new RuntimeException("No integer constant named \"" + constantName + "\" present in type database");
|
|
93 }
|
|
94 }
|
|
95 return i;
|
|
96 }
|
|
97
|
|
98 public Long lookupLongConstant(String constantName) {
|
|
99 return lookupLongConstant(constantName, true);
|
|
100 }
|
|
101
|
|
102 public Long lookupLongConstant(String constantName, boolean throwException) {
|
|
103 Long i = (Long) nameToLongConstantMap.get(constantName);
|
|
104 if (i == null) {
|
|
105 if (throwException) {
|
|
106 throw new RuntimeException("No long constant named \"" + constantName + "\" present in type database");
|
|
107 }
|
|
108 }
|
|
109 return i;
|
|
110 }
|
|
111
|
|
112 public Type getJBooleanType() {
|
|
113 return jbooleanType;
|
|
114 }
|
|
115
|
|
116 public Type getJByteType() {
|
|
117 return jbyteType;
|
|
118 }
|
|
119
|
|
120 public Type getJCharType() {
|
|
121 return jcharType;
|
|
122 }
|
|
123
|
|
124 public Type getJDoubleType() {
|
|
125 return jdoubleType;
|
|
126 }
|
|
127
|
|
128 public Type getJFloatType() {
|
|
129 return jfloatType;
|
|
130 }
|
|
131
|
|
132 public Type getJIntType() {
|
|
133 return jintType;
|
|
134 }
|
|
135
|
|
136 public Type getJLongType() {
|
|
137 return jlongType;
|
|
138 }
|
|
139
|
|
140 public Type getJShortType() {
|
|
141 return jshortType;
|
|
142 }
|
|
143
|
|
144 public long getAddressSize() {
|
|
145 return machDesc.getAddressSize();
|
|
146 }
|
|
147
|
|
148 public long getOopSize() {
|
|
149 return machDesc.getOopSize();
|
|
150 }
|
|
151
|
|
152 public boolean addressTypeIsEqualToType(Address addr, Type type) {
|
|
153 if (addr == null) {
|
|
154 return false;
|
|
155 }
|
|
156
|
|
157 // This implementation should be suitably platform-independent; we
|
|
158 // search nearby memory for the vtbl value of the given type.
|
|
159
|
|
160 Address vtblAddr = vtblAccess.getVtblForType(type);
|
|
161
|
|
162 if (vtblAddr == null) {
|
|
163 // Type was not polymorphic, or an error occurred during lookup
|
|
164 if (DEBUG) {
|
|
165 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: vtblAddr == null");
|
|
166 }
|
|
167
|
|
168 return false;
|
|
169 }
|
|
170
|
|
171 // The first implementation searched three locations for this vtbl
|
|
172 // value; scanning through the entire object was considered, but
|
|
173 // we thought we knew where we were looking, and looking only in
|
|
174 // these specific locations should reduce the probability of
|
|
175 // mistaking random bits as a pointer (although, realistically
|
|
176 // speaking, the likelihood of finding a match between the bit
|
|
177 // pattern of, for example, a double and the vtbl is vanishingly
|
|
178 // small.)
|
|
179 // 1. The first word of the object (should handle MSVC++ as
|
|
180 // well as the SparcWorks compilers with compatibility set to
|
|
181 // v5.0 or greater)
|
|
182 // 2. and 3. The last two Address-aligned words of the part of
|
|
183 // the object defined by its topmost polymorphic superclass.
|
|
184 // This should handle the SparcWorks compilers, v4.2 or
|
|
185 // earlier, as well as any other compilers which place the vptr
|
|
186 // at the end of the user-defined fields of the first base
|
|
187 // class with virtual functions.
|
|
188 //
|
|
189 // Unfortunately this algorithm did not work properly for the
|
|
190 // specific case of the ThreadShadow/Thread inheritance situation,
|
|
191 // because the Solaris compiler seems to cleverly eliminate the
|
|
192 // vtbl for ThreadShadow since the only virtual is empty. (We
|
|
193 // should get rid of the ThreadShadow and fix the include
|
|
194 // databases, but need to postpone this for the present.) The
|
|
195 // current solution performs the three-location check for this
|
|
196 // class and all of its known superclasses rather than just the
|
|
197 // topmost polymorphic one.
|
|
198
|
|
199 Type curType = type;
|
|
200
|
|
201 try {
|
|
202 while (curType != null) {
|
|
203 // Using the size information we have for this type, check the
|
|
204 // three locations described above.
|
|
205
|
|
206 // (1)
|
|
207 if (vtblAddr.equals(addr.getAddressAt(0))) {
|
|
208 return true;
|
|
209 }
|
|
210
|
|
211 // (2)
|
|
212 long offset = curType.getSize();
|
|
213 // I don't think this should be misaligned under any
|
|
214 // circumstances, but I'm not sure (FIXME: also not sure which
|
|
215 // way to go here, up or down -- assuming down)
|
|
216 offset -= (offset % getAddressSize());
|
|
217 if (offset <= 0) {
|
|
218 return false;
|
|
219 }
|
|
220 if (vtblAddr.equals(addr.getAddressAt(offset))) {
|
|
221 return true;
|
|
222 }
|
|
223 offset -= getAddressSize();
|
|
224 if (offset <= 0) {
|
|
225 return false;
|
|
226 }
|
|
227 if (vtblAddr.equals(addr.getAddressAt(offset))) {
|
|
228 return true;
|
|
229 }
|
|
230
|
|
231 curType = curType.getSuperclass();
|
|
232 }
|
|
233 }
|
|
234 catch (Exception e) {
|
|
235 // Any UnmappedAddressExceptions, etc. are a good indication
|
|
236 // that the pointer is not of the specified type
|
|
237 if (DEBUG) {
|
|
238 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: exception occurred during lookup:");
|
|
239 e.printStackTrace();
|
|
240 }
|
|
241
|
|
242 return false;
|
|
243 }
|
|
244
|
|
245 if (DEBUG) {
|
|
246 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: all vptr tests failed for type " +
|
|
247 type.getName());
|
|
248 }
|
|
249
|
|
250 return false;
|
|
251 }
|
|
252
|
|
253 public Type guessTypeForAddress(Address addr) {
|
|
254 for (Iterator iter = getTypes(); iter.hasNext(); ) {
|
|
255 Type t = (Type) iter.next();
|
|
256 if (addressTypeIsEqualToType(addr, t)) {
|
|
257 return t;
|
|
258 }
|
|
259 }
|
|
260 return null;
|
|
261 }
|
|
262
|
|
263 public long cIntegerTypeMaxValue(long sizeInBytes, boolean isUnsigned) {
|
|
264 return machDesc.cIntegerTypeMaxValue(sizeInBytes, isUnsigned);
|
|
265 }
|
|
266
|
|
267 public long cIntegerTypeMinValue(long sizeInBytes, boolean isUnsigned) {
|
|
268 return machDesc.cIntegerTypeMinValue(sizeInBytes, isUnsigned);
|
|
269 }
|
|
270
|
|
271 public Iterator getTypes() {
|
|
272 return nameToTypeMap.values().iterator();
|
|
273 }
|
|
274
|
|
275 public Iterator getIntConstants() {
|
|
276 return nameToIntConstantMap.keySet().iterator();
|
|
277 }
|
|
278
|
|
279 public Iterator getLongConstants() {
|
|
280 return nameToLongConstantMap.keySet().iterator();
|
|
281 }
|
|
282
|
|
283 //--------------------------------------------------------------------------------
|
|
284 // Public routines only for use by the database builder
|
|
285 //
|
|
286
|
|
287 /** This method should only be called by the builder of the
|
|
288 TypeDataBase and at most once */
|
|
289 public void setJBooleanType(Type type) {
|
|
290 jbooleanType = type;
|
|
291 }
|
|
292
|
|
293 /** This method should only be called by the builder of the
|
|
294 TypeDataBase and at most once */
|
|
295 public void setJByteType(Type type) {
|
|
296 jbyteType = type;
|
|
297 }
|
|
298
|
|
299 /** This method should only be called by the builder of the
|
|
300 TypeDataBase and at most once */
|
|
301 public void setJCharType(Type type) {
|
|
302 jcharType = type;
|
|
303 }
|
|
304
|
|
305 /** This method should only be called by the builder of the
|
|
306 TypeDataBase and at most once */
|
|
307 public void setJDoubleType(Type type) {
|
|
308 jdoubleType = type;
|
|
309 }
|
|
310
|
|
311 /** This method should only be called by the builder of the
|
|
312 TypeDataBase and at most once */
|
|
313 public void setJFloatType(Type type) {
|
|
314 jfloatType = type;
|
|
315 }
|
|
316
|
|
317 /** This method should only be called by the builder of the
|
|
318 TypeDataBase and at most once */
|
|
319 public void setJIntType(Type type) {
|
|
320 jintType = type;
|
|
321 }
|
|
322
|
|
323 /** This method should only be called by the builder of the
|
|
324 TypeDataBase and at most once */
|
|
325 public void setJLongType(Type type) {
|
|
326 jlongType = type;
|
|
327 }
|
|
328
|
|
329 /** This method should only be called by the builder of the
|
|
330 TypeDataBase and at most once */
|
|
331 public void setJShortType(Type type) {
|
|
332 jshortType = type;
|
|
333 }
|
|
334
|
|
335 /** This method should only be used by the builder of the
|
|
336 TypeDataBase. Throws a RuntimeException if a class with this
|
|
337 name was already present. */
|
|
338 public void addType(Type type) {
|
|
339 if (nameToTypeMap.get(type.getName()) != null) {
|
|
340 throw new RuntimeException("type of name \"" + type.getName() + "\" already present");
|
|
341 }
|
|
342
|
|
343 nameToTypeMap.put(type.getName(), type);
|
|
344 }
|
|
345
|
|
346 /** This method should only be used by the builder of the
|
|
347 TypeDataBase. Throws a RuntimeException if this class was not
|
|
348 present. */
|
|
349 public void removeType(Type type) {
|
|
350 Type curType = (Type) nameToTypeMap.get(type.getName());
|
|
351 if (curType == null) {
|
|
352 throw new RuntimeException("type of name \"" + type.getName() + "\" not present");
|
|
353 }
|
|
354
|
|
355 if (!curType.equals(type)) {
|
|
356 throw new RuntimeException("a different type of name \"" + type.getName() + "\" was present");
|
|
357 }
|
|
358
|
|
359 nameToTypeMap.remove(type.getName());
|
|
360 }
|
|
361
|
|
362 /** This method should only be used by the builder of the
|
|
363 TypeDataBase. Throws a RuntimeException if an integer constant
|
|
364 with this name was already present. */
|
|
365 public void addIntConstant(String name, int value) {
|
|
366 if (nameToIntConstantMap.get(name) != null) {
|
|
367 throw new RuntimeException("int constant of name \"" + name + "\" already present");
|
|
368 }
|
|
369
|
|
370 nameToIntConstantMap.put(name, new Integer(value));
|
|
371 }
|
|
372
|
|
373 /** This method should only be used by the builder of the
|
|
374 TypeDataBase. Throws a RuntimeException if an integer constant
|
|
375 with this name was not present. */
|
|
376 public void removeIntConstant(String name) {
|
|
377 Integer curConstant = (Integer) nameToIntConstantMap.get(name);
|
|
378 if (curConstant == null) {
|
|
379 throw new RuntimeException("int constant of name \"" + name + "\" not present");
|
|
380 }
|
|
381
|
|
382 nameToIntConstantMap.remove(name);
|
|
383 }
|
|
384
|
|
385 /** This method should only be used by the builder of the
|
|
386 TypeDataBase. Throws a RuntimeException if a long constant with
|
|
387 this name was already present. */
|
|
388 public void addLongConstant(String name, long value) {
|
|
389 if (nameToLongConstantMap.get(name) != null) {
|
|
390 throw new RuntimeException("long constant of name \"" + name + "\" already present");
|
|
391 }
|
|
392
|
|
393 nameToLongConstantMap.put(name, new Long(value));
|
|
394 }
|
|
395
|
|
396 /** This method should only be used by the builder of the
|
|
397 TypeDataBase. Throws a RuntimeException if a long constant with
|
|
398 this name was not present. */
|
|
399 public void removeLongConstant(String name) {
|
|
400 Long curConstant = (Long) nameToLongConstantMap.get(name);
|
|
401 if (curConstant == null) {
|
|
402 throw new RuntimeException("long constant of name \"" + name + "\" not present");
|
|
403 }
|
|
404
|
|
405 nameToLongConstantMap.remove(name);
|
|
406 }
|
|
407 }
|