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