1 /*
   2  * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.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       String symbol = "heapOopSize"; // global int constant and value is initialized at runtime.
 310       addIntConstant(symbol, (int)lookupInProcess(symbol).getCIntegerAt(0, 4, false));
 311   }
 312 
 313   private void readVMLongConstants() {
 314     // Get the variables we need in order to traverse the VMLongConstantEntry[]
 315     long longConstantEntryNameOffset;
 316     long longConstantEntryValueOffset;
 317     long longConstantEntryArrayStride;
 318     
 319     longConstantEntryNameOffset  = getLongValueFromProcess("gHotSpotVMLongConstantEntryNameOffset");
 320     longConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMLongConstantEntryValueOffset");
 321     longConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMLongConstantEntryArrayStride");
 322 
 323     // Fetch the address of the VMLongConstantEntry*
 324     Address entryAddr = lookupInProcess("gHotSpotVMLongConstants");
 325     // Dereference this once to get the pointer to the first VMLongConstantEntry
 326     entryAddr = entryAddr.getAddressAt(0);
 327     if (entryAddr == null) {
 328       throw new RuntimeException("gHotSpotVMLongConstants was not initialized properly in the remote process; can not continue");
 329     }
 330 
 331     // Start iterating down it until we find an entry with no name
 332     Address nameAddr = null;
 333     do {
 334       // Fetch the type name first
 335       nameAddr = entryAddr.getAddressAt(longConstantEntryNameOffset);
 336       if (nameAddr != null) {
 337         String name = CStringUtilities.getString(nameAddr);
 338         int value = (int) entryAddr.getCIntegerAt(longConstantEntryValueOffset, C_INT64_SIZE, true);
 339 
 340         // Be a little resilient
 341         Long oldValue = lookupLongConstant(name, false);
 342         if (oldValue == null) {
 343           addLongConstant(name, value);
 344         } else {
 345           if (oldValue.longValue() != value) {
 346             throw new RuntimeException("Error: the long constant \"" + name +
 347                                        "\" had its value redefined (old was " + oldValue +
 348                                        ", new is " + value + ". Aborting.");
 349           } else {
 350             System.err.println("Warning: the long constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMLongConstants) " +
 351                                "had its value declared as " + value + " twice. Continuing.");
 352           }
 353         }
 354       }
 355 
 356       entryAddr = entryAddr.addOffsetTo(longConstantEntryArrayStride);
 357     } while (nameAddr != null);
 358   }
 359 
 360   private BasicType lookupOrFail(String typeName) {
 361     BasicType type = (BasicType) lookupType(typeName, false);
 362     if (type == null) {
 363       throw new RuntimeException("Type \"" + typeName + "\", referenced in VMStructs::localHotSpotVMStructs in the remote VM, " +
 364                                  "was not present in the remote VMStructs::localHotSpotVMTypes table (should have been caught " +
 365                                  "in the debug build of that VM). Can not continue.");
 366     }
 367     return type;
 368   }
 369 
 370   private long getLongValueFromProcess(String symbol) {
 371     return lookupInProcess(symbol).getCIntegerAt(0, C_INT64_SIZE, true);
 372   }
 373 
 374   private Address lookupInProcess(String symbol) throws NoSuchSymbolException {
 375     // FIXME: abstract away the loadobject name
 376     for (int i = 0; i < jvmLibNames.length; i++) {
 377       Address addr = symbolLookup.lookup(jvmLibNames[i], symbol);
 378       if (addr != null) {
 379         return addr;
 380       }
 381     }
 382     String errStr = "(";
 383     for (int i = 0; i < jvmLibNames.length; i++) {
 384       errStr += jvmLibNames[i];
 385       if (i < jvmLibNames.length - 1) {
 386         errStr += ", ";
 387       }
 388     }
 389     errStr += ")";
 390     throw new NoSuchSymbolException(symbol,
 391                                     "Could not find symbol \"" + symbol +
 392                                     "\" in any of the known library names " +
 393                                     errStr);
 394   }
 395 
 396   private BasicType lookupOrCreateClass(String typeName, boolean isOopType,
 397                                         boolean isIntegerType, boolean isUnsigned) {
 398     BasicType type = (BasicType) lookupType(typeName, false);
 399     if (type == null) {
 400       // Create a new type
 401       type = createBasicType(typeName, isOopType, isIntegerType, isUnsigned);
 402     }
 403     return type;
 404   }
 405 
 406   /** Creates a new BasicType, initializes its size to -1 so we can
 407       test to ensure that all types' sizes are initialized by VMTypes,
 408       and adds it to the database. Takes care of initializing integer
 409       and oop types properly. */
 410   private BasicType createBasicType(String typeName, boolean isOopType,
 411                                     boolean isIntegerType, boolean isUnsigned) {
 412     
 413     BasicType type = null;
 414 
 415     if (isIntegerType) {
 416       type = new BasicCIntegerType(this, typeName, isUnsigned);
 417     } else {
 418       if (typeNameIsPointerType(typeName)) {
 419         type = recursiveCreateBasicPointerType(typeName);
 420       } else {
 421         type = new BasicType(this, typeName);
 422       }
 423 
 424       if (isOopType) {
 425         // HACK: turn markOop into a C integer type. This allows
 426         // proper handling of it in the Serviceability Agent. (FIXME
 427         // -- consider doing something different here)
 428         if (typeName.equals("markOop")) {
 429           type = new BasicCIntegerType(this, typeName, true);
 430         } else {
 431           type.setIsOopType(true);
 432         }
 433       }
 434     }
 435 
 436     type.setSize(UNINITIALIZED_SIZE);
 437     addType(type);
 438     return type;
 439   }
 440   
 441   /** Recursively creates a PointerType from the string representation
 442       of the type's name. Note that this currently needs some
 443       workarounds due to incomplete information in the VMStructs
 444       database. */
 445   private BasicPointerType recursiveCreateBasicPointerType(String typeName) {
 446     String targetTypeName = typeName.substring(0, typeName.lastIndexOf('*')).trim();
 447     Type targetType = null;
 448     if (typeNameIsPointerType(targetTypeName)) {
 449       targetType = recursiveCreateBasicPointerType(targetTypeName);
 450     } else {
 451       targetType = lookupType(targetTypeName, false);
 452       if (targetType == null) {
 453         // Workaround for missing C integer types in database.
 454         // Also looks like we can't throw an exception for other
 455         // missing target types because there are some in old
 456         // VMStructs tables that didn't have the target type declared.
 457         // For this case, we create basic types that never get filled
 458         // in.
 459         
 460         if (targetTypeName.equals("char") ||
 461             targetTypeName.equals("const char")) {
 462           // We don't have a representation of const-ness of C types in the SA
 463           BasicType basicTargetType = createBasicType(targetTypeName, false, true, false);
 464           basicTargetType.setSize(1);
 465           targetType = basicTargetType;
 466         } else if (targetTypeName.equals("u_char")) {
 467           BasicType basicTargetType = createBasicType(targetTypeName, false, true, true);
 468           basicTargetType.setSize(1);
 469           targetType = basicTargetType;
 470         } else {
 471           if (DEBUG) {
 472             System.err.println("WARNING: missing target type \"" + targetTypeName + "\" for pointer type \"" + typeName + "\"");
 473           }
 474           targetType = createBasicType(targetTypeName, false, false, false);
 475         }
 476       }
 477     }
 478     return new BasicPointerType(this, typeName, targetType);
 479   }
 480 
 481   private boolean typeNameIsPointerType(String typeName) {
 482     int i = typeName.length() - 1;
 483     while (i >= 0 && Character.isWhitespace(typeName.charAt(i))) {
 484       --i;
 485     }
 486     if (i >= 0 && typeName.charAt(i) == '*') {
 487       return true;
 488     }
 489     return false;
 490   }
 491 
 492     public void createType(String typeName, String superclassName,
 493                            boolean isOopType, boolean isIntegerType,
 494                            boolean isUnsigned, long size) {
 495         // See whether we have a superclass
 496         BasicType superclass = null;
 497         if (superclassName != null) {
 498             // Fetch or create it (FIXME: would get oop types wrong if
 499             // they had a hierarchy; consider using lookupOrFail)
 500             superclass = lookupOrCreateClass(superclassName, false, false, false);
 501         }
 502         
 503         // Lookup or create the current type
 504         BasicType curType = lookupOrCreateClass(typeName, isOopType, isIntegerType, isUnsigned);
 505         // Set superclass and/or ensure it's correct
 506         if (superclass != null) {
 507             if (curType.getSuperclass() == null) {
 508                 // Set the superclass in the current type
 509                 curType.setSuperclass(superclass);
 510             }
 511 
 512             if (curType.getSuperclass() != superclass) {
 513                 throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
 514                                            "had its superclass redefined (old was " + curType.getSuperclass().getName() + ", new is " +
 515                                            superclass.getName() + ").");
 516             }
 517         }
 518 
 519         // Classes are created with a size of UNINITIALIZED_SIZE.
 520         // Set size if necessary.
 521         if (curType.getSize() == UNINITIALIZED_SIZE) {
 522             curType.setSize(size);
 523         } else {
 524             if (curType.getSize() != size) {
 525                 throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
 526                                            "had its size redefined (old was " + curType.getSize() + ", new is " + size + ").");
 527             }
 528 
 529             System.err.println("Warning: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
 530                                "had its size declared as " + size + " twice. Continuing.");
 531         }
 532 
 533     }
 534 
 535     /** "Virtual constructor" for fields based on type */
 536     public void createField(BasicType containingType,
 537                             String name, Type type, boolean isStatic,
 538                             long offset, Address staticFieldAddress) {
 539         // Add field to containing type
 540         containingType.addField(internalCreateField(containingType, name, type, isStatic, offset, staticFieldAddress));
 541     }
 542 
 543     Field internalCreateField(BasicType containingType,
 544                               String name, Type type, boolean isStatic,
 545                               long offset, Address staticFieldAddress) {
 546     // "Virtual constructor" based on type
 547     if (type.isOopType()) {
 548       return new BasicOopField(this, containingType, name, type,
 549                                isStatic, offset, staticFieldAddress);
 550     }
 551 
 552     if (type instanceof CIntegerType) {
 553       return new BasicCIntegerField(this, containingType, name, type,
 554                                     isStatic, offset, staticFieldAddress);
 555     }
 556 
 557     if (type.equals(getJBooleanType())) {
 558       return new BasicJBooleanField(this, containingType, name, type,
 559                                     isStatic, offset, staticFieldAddress);
 560     }
 561     
 562     if (type.equals(getJByteType())) {
 563       return new BasicJByteField(this, containingType, name, type,
 564                                  isStatic, offset, staticFieldAddress);
 565     }
 566     
 567     if (type.equals(getJCharType())) {
 568       return new BasicJCharField(this, containingType, name, type,
 569                                  isStatic, offset, staticFieldAddress);
 570     }
 571     
 572     if (type.equals(getJDoubleType())) {
 573       return new BasicJDoubleField(this, containingType, name, type,
 574                                    isStatic, offset, staticFieldAddress);
 575     }
 576     
 577     if (type.equals(getJFloatType())) {
 578       return new BasicJFloatField(this, containingType, name, type,
 579                                   isStatic, offset, staticFieldAddress);
 580     }
 581     
 582     if (type.equals(getJIntType())) {
 583       return new BasicJIntField(this, containingType, name, type,
 584                                 isStatic, offset, staticFieldAddress);
 585     }
 586     
 587     if (type.equals(getJLongType())) {
 588       return new BasicJLongField(this, containingType, name, type,
 589                                  isStatic, offset, staticFieldAddress);
 590     }
 591     
 592     if (type.equals(getJShortType())) {
 593       return new BasicJShortField(this, containingType, name, type,
 594                                   isStatic, offset, staticFieldAddress);
 595     }
 596     
 597     // Unknown ("opaque") type. Instantiate ordinary Field.
 598     return new BasicField(this, containingType, name, type,
 599                           isStatic, offset, staticFieldAddress);
 600   }
 601 
 602   // For debugging
 603   private void dumpMemory(Address addr, int len) {
 604     int i = 0;
 605     while (i < len) {
 606       System.err.print(addr.addOffsetTo(i) + ":");
 607       for (int j = 0; j < 8 && i < len; i++, j++) {
 608         String s = Long.toHexString(addr.getCIntegerAt(i, 1, true));
 609         System.err.print(" 0x");
 610         for (int k = 0; k < 2 - s.length(); k++) {
 611           System.err.print("0");
 612         }
 613         System.err.print(s);
 614       }
 615       System.err.println();
 616     }
 617   }
 618 }