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 25 package sun.jvm.hotspot.types.basic; 26 27 import java.util.HashMap; 28 import java.util.Iterator; 29 import java.util.Map; 30 31 import sun.jvm.hotspot.debugger.Address; 32 import sun.jvm.hotspot.debugger.MachineDescription; 33 import sun.jvm.hotspot.runtime.VM; 34 import sun.jvm.hotspot.types.Type; 35 import 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 48 public 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 }