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