1 /* 2 * Copyright (c) 2000, 2011, 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 static HashMap typeToVtbl = new HashMap(); 154 155 private Address vtblForType(Type type) { 156 Address vtblAddr = (Address)typeToVtbl.get(type); 157 if (vtblAddr == null) { 158 vtblAddr = vtblAccess.getVtblForType(type); 159 if (vtblAddr != null) { 160 typeToVtbl.put(type, vtblAddr); 161 } 162 } 163 return vtblAddr; 164 } 165 166 public boolean addressTypeIsEqualToType(Address addr, Type type) { 167 if (addr == null) { 168 return false; 169 } 170 171 // This implementation should be suitably platform-independent; we 172 // search nearby memory for the vtbl value of the given type. 173 174 Address vtblAddr = vtblForType(type); 175 176 if (vtblAddr == null) { 177 // Type was not polymorphic, or an error occurred during lookup 178 if (DEBUG) { 179 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: vtblAddr == null"); 180 } 181 182 return false; 183 } 184 185 // The first implementation searched three locations for this vtbl 186 // value; scanning through the entire object was considered, but 187 // we thought we knew where we were looking, and looking only in 188 // these specific locations should reduce the probability of 189 // mistaking random bits as a pointer (although, realistically 190 // speaking, the likelihood of finding a match between the bit 191 // pattern of, for example, a double and the vtbl is vanishingly 192 // small.) 193 // 1. The first word of the object (should handle MSVC++ as 194 // well as the SparcWorks compilers with compatibility set to 195 // v5.0 or greater) 196 // 2. and 3. The last two Address-aligned words of the part of 197 // the object defined by its topmost polymorphic superclass. 198 // This should handle the SparcWorks compilers, v4.2 or 199 // earlier, as well as any other compilers which place the vptr 200 // at the end of the user-defined fields of the first base 201 // class with virtual functions. 202 // 203 // Unfortunately this algorithm did not work properly for the 204 // specific case of the ThreadShadow/Thread inheritance situation, 205 // because the Solaris compiler seems to cleverly eliminate the 206 // vtbl for ThreadShadow since the only virtual is empty. (We 207 // should get rid of the ThreadShadow and fix the include 208 // databases, but need to postpone this for the present.) The 209 // current solution performs the three-location check for this 210 // class and all of its known superclasses rather than just the 211 // topmost polymorphic one. 212 213 Type curType = type; 214 215 try { 216 while (curType != null) { 217 // Using the size information we have for this type, check the 218 // three locations described above. 219 220 // (1) 221 if (vtblAddr.equals(addr.getAddressAt(0))) { 222 return true; 223 } 224 225 // (2) 226 long offset = curType.getSize(); 227 // I don't think this should be misaligned under any 228 // circumstances, but I'm not sure (FIXME: also not sure which 229 // way to go here, up or down -- assuming down) 230 offset -= (offset % getAddressSize()); 231 if (offset <= 0) { 232 return false; 233 } 234 if (vtblAddr.equals(addr.getAddressAt(offset))) { 235 return true; 236 } 237 offset -= getAddressSize(); 238 if (offset <= 0) { 239 return false; 240 } 241 if (vtblAddr.equals(addr.getAddressAt(offset))) { 242 return true; 243 } 244 245 curType = curType.getSuperclass(); 246 } 247 } 248 catch (Exception e) { 249 // Any UnmappedAddressExceptions, etc. are a good indication 250 // that the pointer is not of the specified type 251 if (DEBUG) { 252 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: exception occurred during lookup:"); 253 e.printStackTrace(); 254 } 255 256 return false; 257 } 258 259 if (DEBUG) { 260 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: all vptr tests failed for type " + 261 type.getName()); 262 } 263 264 return false; 265 } 266 267 public Type findDynamicTypeForAddress(Address addr, Type baseType) { 268 // This implementation should be suitably platform-independent; we 269 // search nearby memory for the vtbl value of the given type. 270 271 if (vtblForType(baseType) == null) { 272 // Type was not polymorphic which is an error of some sort 273 throw new InternalError(baseType + " does not appear to be polymorphic"); 274 } 275 276 // This is a more restricted version of guessTypeForAddress since 277 // that function has some limitations since it doesn't really know 278 // where in the hierarchy a virtual type starts and just poking 279 // around in memory is likely to trip over some vtable address, 280 // resulting in false positives. Eventually all uses should 281 // switch to this logic but in the interests of stability it will 282 // be separate for the moment. 283 284 // Assuming that the base type is truly the first polymorphic type 285 // then the vtbl for all subclasss should be at several defined 286 // locations so only those locations will be checked. It's also 287 // required that the caller knows that the static type is at least 288 // baseType. See the notes in guessTypeForAddress for the logic of 289 // the locations searched. 290 291 Address loc1 = addr.getAddressAt(0); 292 Address loc2 = null; 293 Address loc3 = null; 294 long offset2 = baseType.getSize(); 295 // I don't think this should be misaligned under any 296 // circumstances, but I'm not sure (FIXME: also not sure which 297 // way to go here, up or down -- assuming down) 298 offset2 = offset2 - (offset2 % getAddressSize()) - getAddressSize(); 299 if (offset2 > 0) { 300 loc2 = addr.getAddressAt(offset2); 301 } 302 long offset3 = offset2 - getAddressSize(); 303 if (offset3 > 0) { 304 loc3 = addr.getAddressAt(offset3); 305 } 306 307 Type loc2Match = null; 308 Type loc3Match = null; 309 for (Iterator iter = getTypes(); iter.hasNext(); ) { 310 Type type = (Type) iter.next(); 311 Type superClass = type; 312 while (superClass != baseType && superClass != null) { 313 superClass = superClass.getSuperclass(); 314 } 315 if (superClass == null) continue; 316 Address vtblAddr = vtblForType(type); 317 if (vtblAddr == null) { 318 // This occurs sometimes for intermediate types that are never 319 // instantiated. 320 if (DEBUG) { 321 System.err.println("null vtbl for " + type); 322 } 323 continue; 324 } 325 // Prefer loc1 match 326 if (vtblAddr.equals(loc1)) return type; 327 if (loc2 != null && loc2Match == null && vtblAddr.equals(loc2)) { 328 loc2Match = type; 329 } 330 if (loc3 != null && loc3Match == null && vtblAddr.equals(loc3)) { 331 loc3Match = type; 332 } 333 } 334 if (loc2Match != null) return loc2Match; 335 if (loc3Match != null) return loc3Match; 336 return null; 337 } 338 339 public Type guessTypeForAddress(Address addr) { 340 for (Iterator iter = getTypes(); iter.hasNext(); ) { 341 Type t = (Type) iter.next(); 342 if (addressTypeIsEqualToType(addr, t)) { 343 return t; 344 } 345 } 346 return null; 347 } 348 349 public long cIntegerTypeMaxValue(long sizeInBytes, boolean isUnsigned) { 350 return machDesc.cIntegerTypeMaxValue(sizeInBytes, isUnsigned); 351 } 352 353 public long cIntegerTypeMinValue(long sizeInBytes, boolean isUnsigned) { 354 return machDesc.cIntegerTypeMinValue(sizeInBytes, isUnsigned); 355 } 356 357 public Iterator getTypes() { 358 return nameToTypeMap.values().iterator(); 359 } 360 361 public Iterator getIntConstants() { 362 return nameToIntConstantMap.keySet().iterator(); 363 } 364 365 public Iterator getLongConstants() { 366 return nameToLongConstantMap.keySet().iterator(); 367 } 368 369 //-------------------------------------------------------------------------------- 370 // Public routines only for use by the database builder 371 // 372 373 /** This method should only be called by the builder of the 374 TypeDataBase and at most once */ 375 public void setJBooleanType(Type type) { 376 jbooleanType = type; 377 } 378 379 /** This method should only be called by the builder of the 380 TypeDataBase and at most once */ 381 public void setJByteType(Type type) { 382 jbyteType = type; 383 } 384 385 /** This method should only be called by the builder of the 386 TypeDataBase and at most once */ 387 public void setJCharType(Type type) { 388 jcharType = type; 389 } 390 391 /** This method should only be called by the builder of the 392 TypeDataBase and at most once */ 393 public void setJDoubleType(Type type) { 394 jdoubleType = type; 395 } 396 397 /** This method should only be called by the builder of the 398 TypeDataBase and at most once */ 399 public void setJFloatType(Type type) { 400 jfloatType = type; 401 } 402 403 /** This method should only be called by the builder of the 404 TypeDataBase and at most once */ 405 public void setJIntType(Type type) { 406 jintType = type; 407 } 408 409 /** This method should only be called by the builder of the 410 TypeDataBase and at most once */ 411 public void setJLongType(Type type) { 412 jlongType = type; 413 } 414 415 /** This method should only be called by the builder of the 416 TypeDataBase and at most once */ 417 public void setJShortType(Type type) { 418 jshortType = type; 419 } 420 421 /** This method should only be used by the builder of the 422 TypeDataBase. Throws a RuntimeException if a class with this 423 name was already present. */ 424 public void addType(Type type) { 425 if (nameToTypeMap.get(type.getName()) != null) { 426 throw new RuntimeException("type of name \"" + type.getName() + "\" already present"); 427 } 428 429 nameToTypeMap.put(type.getName(), type); 430 } 431 432 /** This method should only be used by the builder of the 433 TypeDataBase. Throws a RuntimeException if this class was not 434 present. */ 435 public void removeType(Type type) { 436 Type curType = (Type) nameToTypeMap.get(type.getName()); 437 if (curType == null) { 438 throw new RuntimeException("type of name \"" + type.getName() + "\" not present"); 439 } 440 441 if (!curType.equals(type)) { 442 throw new RuntimeException("a different type of name \"" + type.getName() + "\" was present"); 443 } 444 445 nameToTypeMap.remove(type.getName()); 446 } 447 448 /** This method should only be used by the builder of the 449 TypeDataBase. Throws a RuntimeException if an integer constant 450 with this name was already present. */ 451 public void addIntConstant(String name, int value) { 452 if (nameToIntConstantMap.get(name) != null) { 453 throw new RuntimeException("int constant of name \"" + name + "\" already present"); 454 } 455 456 nameToIntConstantMap.put(name, new Integer(value)); 457 } 458 459 /** This method should only be used by the builder of the 460 TypeDataBase. Throws a RuntimeException if an integer constant 461 with this name was not present. */ 462 public void removeIntConstant(String name) { 463 Integer curConstant = (Integer) nameToIntConstantMap.get(name); 464 if (curConstant == null) { 465 throw new RuntimeException("int constant of name \"" + name + "\" not present"); 466 } 467 468 nameToIntConstantMap.remove(name); 469 } 470 471 /** This method should only be used by the builder of the 472 TypeDataBase. Throws a RuntimeException if a long constant with 473 this name was already present. */ 474 public void addLongConstant(String name, long value) { 475 if (nameToLongConstantMap.get(name) != null) { 476 throw new RuntimeException("long constant of name \"" + name + "\" already present"); 477 } 478 479 nameToLongConstantMap.put(name, new Long(value)); 480 } 481 482 /** This method should only be used by the builder of the 483 TypeDataBase. Throws a RuntimeException if a long constant with 484 this name was not present. */ 485 public void removeLongConstant(String name) { 486 Long curConstant = (Long) nameToLongConstantMap.get(name); 487 if (curConstant == null) { 488 throw new RuntimeException("long constant of name \"" + name + "\" not present"); 489 } 490 491 nameToLongConstantMap.remove(name); 492 } 493 }