1 /*
   2  * Copyright (c) 2000, 2009, 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,
  20  * CA 94065 USA or visit www.oracle.com if you need additional information or
  21  * have any questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.debugger.*;
  30 import sun.jvm.hotspot.types.*;
  31 import sun.jvm.hotspot.types.basic.*;
  32 import sun.jvm.hotspot.utilities.*;
  33 
  34 /** <P> This is the cross-platform TypeDataBase used by the Oop
  35     hierarchy. The decision was made to make this cross-platform by
  36     having the VM export the necessary symbols via a built-in table;
  37     see src/share/vm/runtime/vmStructs.[ch]pp for more details. </P>
  38 
  39     <P> <B>WARNING</B>: clients should refer to this class through the
  40     TypeDataBase interface and not directly to the HotSpotTypeDataBase
  41     type. </P>
  42 
  43     <P> NOTE: since we are fetching the sizes of the Java primitive types
  44  */
  45 
  46 public class HotSpotTypeDataBase extends BasicTypeDataBase {
  47   private Debugger symbolLookup;
  48   private String[] jvmLibNames;
  49   private static final int UNINITIALIZED_SIZE = -1;
  50   private static final int C_INT8_SIZE  = 1;
  51   private static final int C_INT32_SIZE = 4;
  52   private static final int C_INT64_SIZE = 8;
  53 
  54   private static final boolean DEBUG;
  55   static {
  56     DEBUG = System.getProperty("sun.jvm.hotspot.HotSpotTypeDataBase.DEBUG")
  57             != null;
  58   }
  59 
  60   /** <P> This requires a SymbolLookup mechanism as well as the
  61       MachineDescription. Note that we do not need a NameMangler since
  62       we use the vmStructs mechanism to avoid looking up C++
  63       symbols. </P>
  64 
  65       <P> NOTE that it is guaranteed that this constructor will not
  66       attempt to fetch any Java values from the remote process, only C
  67       integers and addresses. This is required because we are fetching
  68       the sizes of the Java primitive types from the remote process,
  69       implying that attempting to fetch them before their sizes are
  70       known is illegal. </P>
  71 
  72       <P> Throws NoSuchSymbolException if a problem occurred while
  73       looking up one of the bootstrapping symbols related to the
  74       VMStructs table in the remote VM; this may indicate that the
  75       remote process is not actually a HotSpot VM. </P>
  76   */
  77   public HotSpotTypeDataBase(MachineDescription machDesc,
  78                              VtblAccess vtblAccess,
  79                              Debugger symbolLookup,
  80                              String[] jvmLibNames) throws NoSuchSymbolException {
  81     super(machDesc, vtblAccess);
  82     this.symbolLookup = symbolLookup;
  83     this.jvmLibNames = jvmLibNames;
  84 
  85     readVMTypes();
  86     initializePrimitiveTypes();
  87     readVMStructs();
  88     readVMIntConstants();
  89     readVMLongConstants();
  90   }
  91 
  92   private void readVMTypes() {
  93     // Get the variables we need in order to traverse the VMTypeEntry[]
  94     long typeEntryTypeNameOffset;
  95     long typeEntrySuperclassNameOffset;
  96     long typeEntryIsOopTypeOffset;
  97     long typeEntryIsIntegerTypeOffset;
  98     long typeEntryIsUnsignedOffset;
  99     long typeEntrySizeOffset;
 100     long typeEntryArrayStride;
 101 
 102     typeEntryTypeNameOffset       = getLongValueFromProcess("gHotSpotVMTypeEntryTypeNameOffset");
 103     typeEntrySuperclassNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySuperclassNameOffset");
 104     typeEntryIsOopTypeOffset      = getLongValueFromProcess("gHotSpotVMTypeEntryIsOopTypeOffset");
 105     typeEntryIsIntegerTypeOffset  = getLongValueFromProcess("gHotSpotVMTypeEntryIsIntegerTypeOffset");
 106     typeEntryIsUnsignedOffset     = getLongValueFromProcess("gHotSpotVMTypeEntryIsUnsignedOffset");
 107     typeEntrySizeOffset           = getLongValueFromProcess("gHotSpotVMTypeEntrySizeOffset");
 108     typeEntryArrayStride          = getLongValueFromProcess("gHotSpotVMTypeEntryArrayStride");
 109 
 110     // Fetch the address of the VMTypeEntry*
 111     Address entryAddr = lookupInProcess("gHotSpotVMTypes");
 112     //    System.err.println("gHotSpotVMTypes address = " + entryAddr);
 113     // Dereference this once to get the pointer to the first VMTypeEntry
 114     //    dumpMemory(entryAddr, 80);
 115     entryAddr = entryAddr.getAddressAt(0);
 116 
 117     if (entryAddr == null) {
 118       throw new RuntimeException("gHotSpotVMTypes was not initialized properly in the remote process; can not continue");
 119     }
 120 
 121     // Start iterating down it until we find an entry with no name
 122     Address typeNameAddr = null;
 123     do {
 124       // Fetch the type name first
 125       typeNameAddr = entryAddr.getAddressAt(typeEntryTypeNameOffset);
 126       if (typeNameAddr != null) {
 127         String typeName = CStringUtilities.getString(typeNameAddr);
 128 
 129         String superclassName = null;
 130         Address superclassNameAddr = entryAddr.getAddressAt(typeEntrySuperclassNameOffset);
 131         if (superclassNameAddr != null) {
 132           superclassName = CStringUtilities.getString(superclassNameAddr);
 133         }
 134 
 135         boolean isOopType     = (entryAddr.getCIntegerAt(typeEntryIsOopTypeOffset, C_INT32_SIZE, false) != 0);
 136         boolean isIntegerType = (entryAddr.getCIntegerAt(typeEntryIsIntegerTypeOffset, C_INT32_SIZE, false) != 0);
 137         boolean isUnsigned    = (entryAddr.getCIntegerAt(typeEntryIsUnsignedOffset, C_INT32_SIZE, false) != 0);
 138         long size             = entryAddr.getCIntegerAt(typeEntrySizeOffset, C_INT64_SIZE, true);
 139 
 140         createType(typeName, superclassName, isOopType, isIntegerType, isUnsigned, size);
 141       }
 142 
 143       entryAddr = entryAddr.addOffsetTo(typeEntryArrayStride);
 144     } while (typeNameAddr != null);
 145   }
 146 
 147   private void initializePrimitiveTypes() {
 148     // Look up the needed primitive types by name...they had better be present
 149     setJBooleanType(lookupPrimitiveType("jboolean"));
 150     setJByteType   (lookupPrimitiveType("jbyte"));
 151     setJCharType   (lookupPrimitiveType("jchar"));
 152     setJDoubleType (lookupPrimitiveType("jdouble"));
 153     setJFloatType  (lookupPrimitiveType("jfloat"));
 154     setJIntType    (lookupPrimitiveType("jint"));
 155     setJLongType   (lookupPrimitiveType("jlong"));
 156     setJShortType  (lookupPrimitiveType("jshort"));
 157 
 158     // Indicate that these are the Java primitive types
 159     ((BasicType) getJBooleanType()).setIsJavaPrimitiveType(true);
 160     ((BasicType) getJByteType()).setIsJavaPrimitiveType(true);
 161     ((BasicType) getJCharType()).setIsJavaPrimitiveType(true);
 162     ((BasicType) getJDoubleType()).setIsJavaPrimitiveType(true);
 163     ((BasicType) getJFloatType()).setIsJavaPrimitiveType(true);
 164     ((BasicType) getJIntType()).setIsJavaPrimitiveType(true);
 165     ((BasicType) getJLongType()).setIsJavaPrimitiveType(true);
 166     ((BasicType) getJShortType()).setIsJavaPrimitiveType(true);
 167   }
 168 
 169   private Type lookupPrimitiveType(String typeName) {
 170     Type type = lookupType(typeName, false);
 171     if (type == null) {
 172       throw new RuntimeException("Error initializing the HotSpotDataBase: could not find the primitive type \"" +
 173                                  typeName + "\" in the remote VM's VMStructs table. This type is required in " +
 174                                  "order to determine the size of Java primitive types. Can not continue.");
 175     }
 176     return type;
 177   }
 178 
 179   private void readVMStructs() {
 180     // Get the variables we need in order to traverse the VMStructEntry[]
 181     long structEntryTypeNameOffset;
 182     long structEntryFieldNameOffset;
 183     long structEntryTypeStringOffset;
 184     long structEntryIsStaticOffset;
 185     long structEntryOffsetOffset;
 186     long structEntryAddressOffset;
 187     long structEntryArrayStride;
 188 
 189     structEntryTypeNameOffset     = getLongValueFromProcess("gHotSpotVMStructEntryTypeNameOffset");
 190     structEntryFieldNameOffset    = getLongValueFromProcess("gHotSpotVMStructEntryFieldNameOffset");
 191     structEntryTypeStringOffset   = getLongValueFromProcess("gHotSpotVMStructEntryTypeStringOffset");
 192     structEntryIsStaticOffset     = getLongValueFromProcess("gHotSpotVMStructEntryIsStaticOffset");
 193     structEntryOffsetOffset       = getLongValueFromProcess("gHotSpotVMStructEntryOffsetOffset");
 194     structEntryAddressOffset      = getLongValueFromProcess("gHotSpotVMStructEntryAddressOffset");
 195     structEntryArrayStride        = getLongValueFromProcess("gHotSpotVMStructEntryArrayStride");
 196 
 197     // Fetch the address of the VMStructEntry*
 198     Address entryAddr = lookupInProcess("gHotSpotVMStructs");
 199     // Dereference this once to get the pointer to the first VMStructEntry
 200     entryAddr = entryAddr.getAddressAt(0);
 201     if (entryAddr == null) {
 202       throw new RuntimeException("gHotSpotVMStructs was not initialized properly in the remote process; can not continue");
 203     }
 204 
 205     // Start iterating down it until we find an entry with no name
 206     Address fieldNameAddr = null;
 207     String typeName = null;
 208     String fieldName = null;
 209     String typeString = null;
 210     boolean isStatic = false;
 211     long offset = 0;
 212     Address staticFieldAddr = null;
 213     long size = 0;
 214     long index = 0;
 215     String opaqueName = "<opaque>";
 216     lookupOrCreateClass(opaqueName, false, false, false);
 217 
 218     do {
 219       // Fetch the field name first
 220       fieldNameAddr = entryAddr.getAddressAt(structEntryFieldNameOffset);
 221       if (fieldNameAddr != null) {
 222         fieldName = CStringUtilities.getString(fieldNameAddr);
 223 
 224         // Now the rest of the names. Keep in mind that the type name
 225         // may be NULL, indicating that the type is opaque.
 226         Address addr = entryAddr.getAddressAt(structEntryTypeNameOffset);
 227         if (addr == null) {
 228           throw new RuntimeException("gHotSpotVMStructs unexpectedly had a NULL type name at index " + index);
 229         }
 230         typeName = CStringUtilities.getString(addr);
 231 
 232         addr = entryAddr.getAddressAt(structEntryTypeStringOffset);
 233         if (addr == null) {
 234           typeString = opaqueName;
 235         } else {
 236           typeString = CStringUtilities.getString(addr);
 237         }
 238 
 239         isStatic = !(entryAddr.getCIntegerAt(structEntryIsStaticOffset, C_INT32_SIZE, false) == 0);
 240         if (isStatic) {
 241           staticFieldAddr = entryAddr.getAddressAt(structEntryAddressOffset);
 242           offset = 0;
 243         } else {
 244           offset = entryAddr.getCIntegerAt(structEntryOffsetOffset, C_INT64_SIZE, true);
 245           staticFieldAddr = null;
 246         }
 247 
 248         // The containing Type must already be in the database -- no exceptions
 249         BasicType containingType = lookupOrFail(typeName);
 250 
 251         // The field's Type must already be in the database -- no exceptions
 252         BasicType fieldType = lookupOrFail(typeString);
 253 
 254         // Create field by type
 255         createField(containingType, fieldName, fieldType,
 256                     isStatic, offset, staticFieldAddr);
 257       }
 258 
 259       ++index;
 260       entryAddr = entryAddr.addOffsetTo(structEntryArrayStride);
 261     } while (fieldNameAddr != null);
 262   }
 263 
 264   private void readVMIntConstants() {
 265     // Get the variables we need in order to traverse the VMIntConstantEntry[]
 266     long intConstantEntryNameOffset;
 267     long intConstantEntryValueOffset;
 268     long intConstantEntryArrayStride;
 269 
 270     intConstantEntryNameOffset  = getLongValueFromProcess("gHotSpotVMIntConstantEntryNameOffset");
 271     intConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMIntConstantEntryValueOffset");
 272     intConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMIntConstantEntryArrayStride");
 273 
 274     // Fetch the address of the VMIntConstantEntry*
 275     Address entryAddr = lookupInProcess("gHotSpotVMIntConstants");
 276     // Dereference this once to get the pointer to the first VMIntConstantEntry
 277     entryAddr = entryAddr.getAddressAt(0);
 278     if (entryAddr == null) {
 279       throw new RuntimeException("gHotSpotVMIntConstants was not initialized properly in the remote process; can not continue");
 280     }
 281 
 282     // Start iterating down it until we find an entry with no name
 283     Address nameAddr = null;
 284     do {
 285       // Fetch the type name first
 286       nameAddr = entryAddr.getAddressAt(intConstantEntryNameOffset);
 287       if (nameAddr != null) {
 288         String name = CStringUtilities.getString(nameAddr);
 289         int value = (int) entryAddr.getCIntegerAt(intConstantEntryValueOffset, C_INT32_SIZE, false);
 290 
 291         // Be a little resilient
 292         Integer oldValue = lookupIntConstant(name, false);
 293         if (oldValue == null) {
 294           addIntConstant(name, value);
 295         } else {
 296           if (oldValue.intValue() != value) {
 297             throw new RuntimeException("Error: the integer constant \"" + name +
 298                                        "\" had its value redefined (old was " + oldValue +
 299                                        ", new is " + value + ". Aborting.");
 300           } else {
 301             System.err.println("Warning: the int constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMIntConstants) " +
 302                                "had its value declared as " + value + " twice. Continuing.");
 303           }
 304         }
 305       }
 306 
 307       entryAddr = entryAddr.addOffsetTo(intConstantEntryArrayStride);
 308     } while (nameAddr != null);
 309   }
 310 
 311   private void readVMLongConstants() {
 312     // Get the variables we need in order to traverse the VMLongConstantEntry[]
 313     long longConstantEntryNameOffset;
 314     long longConstantEntryValueOffset;
 315     long longConstantEntryArrayStride;
 316 
 317     longConstantEntryNameOffset  = getLongValueFromProcess("gHotSpotVMLongConstantEntryNameOffset");
 318     longConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMLongConstantEntryValueOffset");
 319     longConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMLongConstantEntryArrayStride");
 320 
 321     // Fetch the address of the VMLongConstantEntry*
 322     Address entryAddr = lookupInProcess("gHotSpotVMLongConstants");
 323     // Dereference this once to get the pointer to the first VMLongConstantEntry
 324     entryAddr = entryAddr.getAddressAt(0);
 325     if (entryAddr == null) {
 326       throw new RuntimeException("gHotSpotVMLongConstants was not initialized properly in the remote process; can not continue");
 327     }
 328 
 329     // Start iterating down it until we find an entry with no name
 330     Address nameAddr = null;
 331     do {
 332       // Fetch the type name first
 333       nameAddr = entryAddr.getAddressAt(longConstantEntryNameOffset);
 334       if (nameAddr != null) {
 335         String name = CStringUtilities.getString(nameAddr);
 336         int value = (int) entryAddr.getCIntegerAt(longConstantEntryValueOffset, C_INT64_SIZE, true);
 337 
 338         // Be a little resilient
 339         Long oldValue = lookupLongConstant(name, false);
 340         if (oldValue == null) {
 341           addLongConstant(name, value);
 342         } else {
 343           if (oldValue.longValue() != value) {
 344             throw new RuntimeException("Error: the long constant \"" + name +
 345                                        "\" had its value redefined (old was " + oldValue +
 346                                        ", new is " + value + ". Aborting.");
 347           } else {
 348             System.err.println("Warning: the long constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMLongConstants) " +
 349                                "had its value declared as " + value + " twice. Continuing.");
 350           }
 351         }
 352       }
 353 
 354       entryAddr = entryAddr.addOffsetTo(longConstantEntryArrayStride);
 355     } while (nameAddr != null);
 356   }
 357 
 358   private BasicType lookupOrFail(String typeName) {
 359     BasicType type = (BasicType) lookupType(typeName, false);
 360     if (type == null) {
 361       throw new RuntimeException("Type \"" + typeName + "\", referenced in VMStructs::localHotSpotVMStructs in the remote VM, " +
 362                                  "was not present in the remote VMStructs::localHotSpotVMTypes table (should have been caught " +
 363                                  "in the debug build of that VM). Can not continue.");
 364     }
 365     return type;
 366   }
 367 
 368   private long getLongValueFromProcess(String symbol) {
 369     return lookupInProcess(symbol).getCIntegerAt(0, C_INT64_SIZE, true);
 370   }
 371 
 372   private Address lookupInProcess(String symbol) throws NoSuchSymbolException {
 373     // FIXME: abstract away the loadobject name
 374     for (int i = 0; i < jvmLibNames.length; i++) {
 375       Address addr = symbolLookup.lookup(jvmLibNames[i], symbol);
 376       if (addr != null) {
 377         return addr;
 378       }
 379     }
 380     String errStr = "(";
 381     for (int i = 0; i < jvmLibNames.length; i++) {
 382       errStr += jvmLibNames[i];
 383       if (i < jvmLibNames.length - 1) {
 384         errStr += ", ";
 385       }
 386     }
 387     errStr += ")";
 388     throw new NoSuchSymbolException(symbol,
 389                                     "Could not find symbol \"" + symbol +
 390                                     "\" in any of the known library names " +
 391                                     errStr);
 392   }
 393 
 394   private BasicType lookupOrCreateClass(String typeName, boolean isOopType,
 395                                         boolean isIntegerType, boolean isUnsigned) {
 396     BasicType type = (BasicType) lookupType(typeName, false);
 397     if (type == null) {
 398       // Create a new type
 399       type = createBasicType(typeName, isOopType, isIntegerType, isUnsigned);
 400     }
 401     return type;
 402   }
 403 
 404   /** Creates a new BasicType, initializes its size to -1 so we can
 405       test to ensure that all types' sizes are initialized by VMTypes,
 406       and adds it to the database. Takes care of initializing integer
 407       and oop types properly. */
 408   private BasicType createBasicType(String typeName, boolean isOopType,
 409                                     boolean isIntegerType, boolean isUnsigned) {
 410 
 411     BasicType type = null;
 412 
 413     if (isIntegerType) {
 414       type = new BasicCIntegerType(this, typeName, isUnsigned);
 415     } else {
 416       if (typeNameIsPointerType(typeName)) {
 417         type = recursiveCreateBasicPointerType(typeName);
 418       } else {
 419         type = new BasicType(this, typeName);
 420       }
 421 
 422       if (isOopType) {
 423         // HACK: turn markOop into a C integer type. This allows
 424         // proper handling of it in the Serviceability Agent. (FIXME
 425         // -- consider doing something different here)
 426         if (typeName.equals("markOop")) {
 427           type = new BasicCIntegerType(this, typeName, true);
 428         } else {
 429           type.setIsOopType(true);
 430         }
 431       }
 432     }
 433 
 434     type.setSize(UNINITIALIZED_SIZE);
 435     addType(type);
 436     return type;
 437   }
 438 
 439   /** Recursively creates a PointerType from the string representation
 440       of the type's name. Note that this currently needs some
 441       workarounds due to incomplete information in the VMStructs
 442       database. */
 443   private BasicPointerType recursiveCreateBasicPointerType(String typeName) {
 444     String targetTypeName = typeName.substring(0, typeName.lastIndexOf('*')).trim();
 445     Type targetType = null;
 446     if (typeNameIsPointerType(targetTypeName)) {
 447       targetType = recursiveCreateBasicPointerType(targetTypeName);
 448     } else {
 449       targetType = lookupType(targetTypeName, false);
 450       if (targetType == null) {
 451         // Workaround for missing C integer types in database.
 452         // Also looks like we can't throw an exception for other
 453         // missing target types because there are some in old
 454         // VMStructs tables that didn't have the target type declared.
 455         // For this case, we create basic types that never get filled
 456         // in.
 457 
 458         if (targetTypeName.equals("char") ||
 459             targetTypeName.equals("const char")) {
 460           // We don't have a representation of const-ness of C types in the SA
 461           BasicType basicTargetType = createBasicType(targetTypeName, false, true, false);
 462           basicTargetType.setSize(1);
 463           targetType = basicTargetType;
 464         } else if (targetTypeName.equals("u_char")) {
 465           BasicType basicTargetType = createBasicType(targetTypeName, false, true, true);
 466           basicTargetType.setSize(1);
 467           targetType = basicTargetType;
 468         } else {
 469           if (DEBUG) {
 470             System.err.println("WARNING: missing target type \"" + targetTypeName + "\" for pointer type \"" + typeName + "\"");
 471           }
 472           targetType = createBasicType(targetTypeName, false, false, false);
 473         }
 474       }
 475     }
 476     return new BasicPointerType(this, typeName, targetType);
 477   }
 478 
 479   private boolean typeNameIsPointerType(String typeName) {
 480     int i = typeName.length() - 1;
 481     while (i >= 0 && Character.isWhitespace(typeName.charAt(i))) {
 482       --i;
 483     }
 484     if (i >= 0 && typeName.charAt(i) == '*') {
 485       return true;
 486     }
 487     return false;
 488   }
 489 
 490     public void createType(String typeName, String superclassName,
 491                            boolean isOopType, boolean isIntegerType,
 492                            boolean isUnsigned, long size) {
 493         // See whether we have a superclass
 494         BasicType superclass = null;
 495         if (superclassName != null) {
 496             // Fetch or create it (FIXME: would get oop types wrong if
 497             // they had a hierarchy; consider using lookupOrFail)
 498             superclass = lookupOrCreateClass(superclassName, false, false, false);
 499         }
 500 
 501         // Lookup or create the current type
 502         BasicType curType = lookupOrCreateClass(typeName, isOopType, isIntegerType, isUnsigned);
 503         // Set superclass and/or ensure it's correct
 504         if (superclass != null) {
 505             if (curType.getSuperclass() == null) {
 506                 // Set the superclass in the current type
 507                 curType.setSuperclass(superclass);
 508             }
 509 
 510             if (curType.getSuperclass() != superclass) {
 511                 throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
 512                                            "had its superclass redefined (old was " + curType.getSuperclass().getName() + ", new is " +
 513                                            superclass.getName() + ").");
 514             }
 515         }
 516 
 517         // Classes are created with a size of UNINITIALIZED_SIZE.
 518         // Set size if necessary.
 519         if (curType.getSize() == UNINITIALIZED_SIZE) {
 520             curType.setSize(size);
 521         } else {
 522             if (curType.getSize() != size) {
 523                 throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
 524                                            "had its size redefined (old was " + curType.getSize() + ", new is " + size + ").");
 525             }
 526 
 527             System.err.println("Warning: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
 528                                "had its size declared as " + size + " twice. Continuing.");
 529         }
 530 
 531     }
 532 
 533     /** "Virtual constructor" for fields based on type */
 534     public void createField(BasicType containingType,
 535                             String name, Type type, boolean isStatic,
 536                             long offset, Address staticFieldAddress) {
 537         // Add field to containing type
 538         containingType.addField(internalCreateField(containingType, name, type, isStatic, offset, staticFieldAddress));
 539     }
 540 
 541     Field internalCreateField(BasicType containingType,
 542                               String name, Type type, boolean isStatic,
 543                               long offset, Address staticFieldAddress) {
 544     // "Virtual constructor" based on type
 545     if (type.isOopType()) {
 546       return new BasicOopField(this, containingType, name, type,
 547                                isStatic, offset, staticFieldAddress);
 548     }
 549 
 550     if (type instanceof CIntegerType) {
 551       return new BasicCIntegerField(this, containingType, name, type,
 552                                     isStatic, offset, staticFieldAddress);
 553     }
 554 
 555     if (type.equals(getJBooleanType())) {
 556       return new BasicJBooleanField(this, containingType, name, type,
 557                                     isStatic, offset, staticFieldAddress);
 558     }
 559 
 560     if (type.equals(getJByteType())) {
 561       return new BasicJByteField(this, containingType, name, type,
 562                                  isStatic, offset, staticFieldAddress);
 563     }
 564 
 565     if (type.equals(getJCharType())) {
 566       return new BasicJCharField(this, containingType, name, type,
 567                                  isStatic, offset, staticFieldAddress);
 568     }
 569 
 570     if (type.equals(getJDoubleType())) {
 571       return new BasicJDoubleField(this, containingType, name, type,
 572                                    isStatic, offset, staticFieldAddress);
 573     }
 574 
 575     if (type.equals(getJFloatType())) {
 576       return new BasicJFloatField(this, containingType, name, type,
 577                                   isStatic, offset, staticFieldAddress);
 578     }
 579 
 580     if (type.equals(getJIntType())) {
 581       return new BasicJIntField(this, containingType, name, type,
 582                                 isStatic, offset, staticFieldAddress);
 583     }
 584 
 585     if (type.equals(getJLongType())) {
 586       return new BasicJLongField(this, containingType, name, type,
 587                                  isStatic, offset, staticFieldAddress);
 588     }
 589 
 590     if (type.equals(getJShortType())) {
 591       return new BasicJShortField(this, containingType, name, type,
 592                                   isStatic, offset, staticFieldAddress);
 593     }
 594 
 595     // Unknown ("opaque") type. Instantiate ordinary Field.
 596     return new BasicField(this, containingType, name, type,
 597                           isStatic, offset, staticFieldAddress);
 598   }
 599 
 600   // For debugging
 601   private void dumpMemory(Address addr, int len) {
 602     int i = 0;
 603     while (i < len) {
 604       System.err.print(addr.addOffsetTo(i) + ":");
 605       for (int j = 0; j < 8 && i < len; i++, j++) {
 606         String s = Long.toHexString(addr.getCIntegerAt(i, 1, true));
 607         System.err.print(" 0x");
 608         for (int k = 0; k < 2 - s.length(); k++) {
 609           System.err.print("0");
 610         }
 611         System.err.print(s);
 612       }
 613       System.err.println();
 614     }
 615   }
 616 }