1/*
2 * Copyright (c) 2000, 2012, 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
25package sun.jvm.hotspot;
26
27import java.io.*;
28import java.util.*;
29import sun.jvm.hotspot.debugger.*;
30import sun.jvm.hotspot.types.*;
31import sun.jvm.hotspot.types.basic.*;
32import 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
46public 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  private static int pointerSize = UNINITIALIZED_SIZE;
54  // Counter to ensure read loops terminate:
55  private static final int MAX_DUPLICATE_DEFINITIONS = 100;
56  private int duplicateDefCount = 0;
57
58  private static final boolean DEBUG;
59  static {
60    DEBUG = System.getProperty("sun.jvm.hotspot.HotSpotTypeDataBase.DEBUG")
61            != null;
62  }
63
64  /** <P> This requires a SymbolLookup mechanism as well as the
65      MachineDescription. Note that we do not need a NameMangler since
66      we use the vmStructs mechanism to avoid looking up C++
67      symbols. </P>
68
69      <P> NOTE that it is guaranteed that this constructor will not
70      attempt to fetch any Java values from the remote process, only C
71      integers and addresses. This is required because we are fetching
72      the sizes of the Java primitive types from the remote process,
73      implying that attempting to fetch them before their sizes are
74      known is illegal. </P>
75
76      <P> Throws NoSuchSymbolException if a problem occurred while
77      looking up one of the bootstrapping symbols related to the
78      VMStructs table in the remote VM; this may indicate that the
79      remote process is not actually a HotSpot VM. </P>
80  */
81  public HotSpotTypeDataBase(MachineDescription machDesc,
82                             VtblAccess vtblAccess,
83                             Debugger symbolLookup,
84                             String[] jvmLibNames) throws NoSuchSymbolException {
85    super(machDesc, vtblAccess);
86    this.symbolLookup = symbolLookup;
87    this.jvmLibNames = jvmLibNames;
88
89    readVMTypes();
90    initializePrimitiveTypes();
91    readVMStructs();
92    readVMIntConstants();
93    readVMLongConstants();
94    readExternalDefinitions();
95  }
96
97  public Type lookupType(String cTypeName, boolean throwException) {
98    Type fieldType = super.lookupType(cTypeName, false);
99    if (fieldType == null && cTypeName.startsWith("const ")) {
100      fieldType = (BasicType)lookupType(cTypeName.substring(6), false);
101    }
102    if (fieldType == null && cTypeName.endsWith(" const")) {
103        fieldType = (BasicType)lookupType(cTypeName.substring(0, cTypeName.length() - 6), false);
104    }
105    if (fieldType == null) {
106      if (cTypeName.startsWith("GrowableArray<") && cTypeName.endsWith(">")) {
107        String ttype = cTypeName.substring("GrowableArray<".length(),
108                                            cTypeName.length() - 1);
109        Type templateType = lookupType(ttype, false);
110        if (templateType == null && typeNameIsPointerType(ttype)) {
111          templateType = recursiveCreateBasicPointerType(ttype);
112        }
113        if (templateType == null) {
114          lookupOrFail(ttype);
115        }
116
117        BasicType basicTargetType = createBasicType(cTypeName, false, false, false);
118
119        // transfer fields from GenericGrowableArray to template instance
120        BasicType generic = lookupOrFail("GenericGrowableArray");
121        BasicType specific = lookupOrFail("GrowableArray<int>");
122        basicTargetType.setSize(specific.getSize());
123        Iterator fields = generic.getFields();
124        while (fields.hasNext()) {
125          Field f = (Field)fields.next();
126          basicTargetType.addField(internalCreateField(basicTargetType, f.getName(),
127                                                       f.getType(), f.isStatic(),
128                                                       f.getOffset(), null));
129        }
130        fieldType = basicTargetType;
131      }
132    }
133    if (fieldType == null && typeNameIsPointerType(cTypeName)) {
134      fieldType = recursiveCreateBasicPointerType(cTypeName);
135    }
136    if (fieldType == null && throwException) {
137      super.lookupType(cTypeName, true);
138    }
139    return fieldType;
140  }
141
142  private void readVMTypes() {
143    // Get the variables we need in order to traverse the VMTypeEntry[]
144    long typeEntryTypeNameOffset;
145    long typeEntrySuperclassNameOffset;
146    long typeEntryIsOopTypeOffset;
147    long typeEntryIsIntegerTypeOffset;
148    long typeEntryIsUnsignedOffset;
149    long typeEntrySizeOffset;
150    long typeEntryArrayStride;
151
152    // Fetch the address of the VMTypeEntry*. We get this symbol first
153    // and try to use it to make sure that symbol lookup is working.
154    Address entryAddr = lookupInProcess("gHotSpotVMTypes");
155    //    System.err.println("gHotSpotVMTypes address = " + entryAddr);
156    // Dereference this once to get the pointer to the first VMTypeEntry
157    //    dumpMemory(entryAddr, 80);
158    entryAddr = entryAddr.getAddressAt(0);
159
160    if (entryAddr == null) {
161      throw new RuntimeException("gHotSpotVMTypes was not initialized properly in the remote process; can not continue");
162    }
163
164    typeEntryTypeNameOffset       = getLongValueFromProcess("gHotSpotVMTypeEntryTypeNameOffset");
165    typeEntrySuperclassNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySuperclassNameOffset");
166    typeEntryIsOopTypeOffset      = getLongValueFromProcess("gHotSpotVMTypeEntryIsOopTypeOffset");
167    typeEntryIsIntegerTypeOffset  = getLongValueFromProcess("gHotSpotVMTypeEntryIsIntegerTypeOffset");
168    typeEntryIsUnsignedOffset     = getLongValueFromProcess("gHotSpotVMTypeEntryIsUnsignedOffset");
169    typeEntrySizeOffset           = getLongValueFromProcess("gHotSpotVMTypeEntrySizeOffset");
170    typeEntryArrayStride          = getLongValueFromProcess("gHotSpotVMTypeEntryArrayStride");
171
172    if (typeEntryArrayStride == 0L) {
173      throw new RuntimeException("zero stride: cannot read types.");
174    }
175
176    // Start iterating down it until we find an entry with no name
177    Address typeNameAddr = null;
178    do {
179      // Fetch the type name first
180      typeNameAddr = entryAddr.getAddressAt(typeEntryTypeNameOffset);
181      if (typeNameAddr != null) {
182        String typeName = CStringUtilities.getString(typeNameAddr);
183
184        String superclassName = null;
185        Address superclassNameAddr = entryAddr.getAddressAt(typeEntrySuperclassNameOffset);
186        if (superclassNameAddr != null) {
187          superclassName = CStringUtilities.getString(superclassNameAddr);
188        }
189
190        boolean isOopType     = (entryAddr.getCIntegerAt(typeEntryIsOopTypeOffset, C_INT32_SIZE, false) != 0);
191        boolean isIntegerType = (entryAddr.getCIntegerAt(typeEntryIsIntegerTypeOffset, C_INT32_SIZE, false) != 0);
192        boolean isUnsigned    = (entryAddr.getCIntegerAt(typeEntryIsUnsignedOffset, C_INT32_SIZE, false) != 0);
193        long size             = entryAddr.getCIntegerAt(typeEntrySizeOffset, C_INT64_SIZE, true);
194
195        createType(typeName, superclassName, isOopType, isIntegerType, isUnsigned, size);
196        if (pointerSize == UNINITIALIZED_SIZE && typeName.equals("void*")) {
197          pointerSize = (int)size;
198        }
199      }
200
201      entryAddr = entryAddr.addOffsetTo(typeEntryArrayStride);
202    } while (typeNameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS);
203
204    if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) {
205      throw new RuntimeException("too many duplicate definitions");
206    }
207  }
208
209  private void initializePrimitiveTypes() {
210    // Look up the needed primitive types by name...they had better be present
211    setJBooleanType(lookupPrimitiveType("jboolean"));
212    setJByteType   (lookupPrimitiveType("jbyte"));
213    setJCharType   (lookupPrimitiveType("jchar"));
214    setJDoubleType (lookupPrimitiveType("jdouble"));
215    setJFloatType  (lookupPrimitiveType("jfloat"));
216    setJIntType    (lookupPrimitiveType("jint"));
217    setJLongType   (lookupPrimitiveType("jlong"));
218    setJShortType  (lookupPrimitiveType("jshort"));
219
220    // Indicate that these are the Java primitive types
221    ((BasicType) getJBooleanType()).setIsJavaPrimitiveType(true);
222    ((BasicType) getJByteType()).setIsJavaPrimitiveType(true);
223    ((BasicType) getJCharType()).setIsJavaPrimitiveType(true);
224    ((BasicType) getJDoubleType()).setIsJavaPrimitiveType(true);
225    ((BasicType) getJFloatType()).setIsJavaPrimitiveType(true);
226    ((BasicType) getJIntType()).setIsJavaPrimitiveType(true);
227    ((BasicType) getJLongType()).setIsJavaPrimitiveType(true);
228    ((BasicType) getJShortType()).setIsJavaPrimitiveType(true);
229  }
230
231  private Type lookupPrimitiveType(String typeName) {
232    Type type = lookupType(typeName, false);
233    if (type == null) {
234      throw new RuntimeException("Error initializing the HotSpotDataBase: could not find the primitive type \"" +
235                                 typeName + "\" in the remote VM's VMStructs table. This type is required in " +
236                                 "order to determine the size of Java primitive types. Can not continue.");
237    }
238    return type;
239  }
240
241  private void readExternalDefinitions() {
242    String file = System.getProperty("sun.jvm.hotspot.typedb");
243    if (file != null) {
244      System.out.println("Reading " + file);
245      BufferedReader in = null;
246      try {
247        StreamTokenizer t = new StreamTokenizer(in = new BufferedReader(new InputStreamReader(new FileInputStream(file))));
248        t.resetSyntax();
249        t.wordChars('\u0000','\uFFFF');
250        t.whitespaceChars(' ', ' ');
251        t.whitespaceChars('\n', '\n');
252        t.whitespaceChars('\r', '\r');
253        t.quoteChar('\"');
254        t.eolIsSignificant(true);
255        while (t.nextToken() != StreamTokenizer.TT_EOF) {
256          if (t.ttype == StreamTokenizer.TT_EOL) {
257            continue;
258          }
259
260          if (t.sval.equals("field")) {
261            t.nextToken();
262            BasicType containingType = (BasicType)lookupType(t.sval);
263            t.nextToken();
264            String fieldName = t.sval;
265
266            // The field's Type must already be in the database -- no exceptions
267            t.nextToken();
268            Type fieldType = lookupType(t.sval);
269            t.nextToken();
270            boolean isStatic = Boolean.valueOf(t.sval).booleanValue();
271            t.nextToken();
272            long offset = Long.parseLong(t.sval);
273            t.nextToken();
274            Address staticAddress = null;
275            if (isStatic) {
276              throw new InternalError("static fields not supported");
277            }
278
279            // check to see if the field already exists
280            Iterator i = containingType.getFields();
281            boolean defined = false;
282            while (i.hasNext()) {
283              Field f = (Field) i.next();
284              if (f.getName().equals(fieldName)) {
285                if (f.isStatic() != isStatic) {
286                  throw new RuntimeException("static/nonstatic mismatch: " + fieldName);
287                }
288                if (!isStatic) {
289                  if (f.getOffset() != offset) {
290                    throw new RuntimeException("bad redefinition of field offset: " + fieldName);
291                  }
292                } else {
293                  if (!f.getStaticFieldAddress().equals(staticAddress)) {
294                    throw new RuntimeException("bad redefinition of field location: " + fieldName);
295                  }
296                }
297                if (f.getType() != fieldType) {
298                  System.out.println(fieldType);
299                  System.out.println(f.getType());
300                  throw new RuntimeException("bad redefinition of field type: " + fieldName);
301                }
302                defined = true;
303                break;
304              }
305            }
306
307            if (!defined) {
308              // Create field by type
309              createField(containingType,
310                          fieldName, fieldType,
311                          isStatic,
312                          offset,
313                          staticAddress);
314            }
315          } else if (t.sval.equals("type")) {
316            t.nextToken();
317            String typeName = t.sval;
318            t.nextToken();
319            String superclassName = t.sval;
320            if (superclassName.equals("null")) {
321              superclassName = null;
322            }
323            t.nextToken();
324            boolean isOop = Boolean.valueOf(t.sval).booleanValue();
325            t.nextToken();
326            boolean isInteger = Boolean.valueOf(t.sval).booleanValue();
327            t.nextToken();
328            boolean isUnsigned = Boolean.valueOf(t.sval).booleanValue();
329            t.nextToken();
330            long size = Long.parseLong(t.sval);
331
332            BasicType type = null;
333            try {
334              type = (BasicType)lookupType(typeName);
335            } catch (RuntimeException e) {
336            }
337            if (type != null) {
338              if (type.isOopType() != isOop) {
339                throw new RuntimeException("oop mismatch in type definition: " + typeName);
340              }
341              if (type.isCIntegerType() != isInteger) {
342                throw new RuntimeException("integer type mismatch in type definition: " + typeName);
343              }
344              if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) {
345                throw new RuntimeException("unsigned mismatch in type definition: " + typeName);
346              }
347              if (type.getSuperclass() == null) {
348                if (superclassName != null) {
349                  if (type.getSize() == -1) {
350                    type.setSuperclass(lookupType(superclassName));
351                  } else {
352                    throw new RuntimeException("unexpected superclass in type definition: " + typeName);
353                  }
354                }
355              } else {
356                if (superclassName == null) {
357                  throw new RuntimeException("missing superclass in type definition: " + typeName);
358                }
359                if (!type.getSuperclass().getName().equals(superclassName)) {
360                  throw new RuntimeException("incorrect superclass in type definition: " + typeName);
361                }
362              }
363              if (type.getSize() != size) {
364                if (type.getSize() == -1 || type.getSize() == 0) {
365                  type.setSize(size);
366                } else {
367                  throw new RuntimeException("size mismatch in type definition: " + typeName + ": " + type.getSize() + " != " + size);
368                }
369              }
370            }
371
372            if (lookupType(typeName, false) == null) {
373              // Create type
374              createType(typeName, superclassName, isOop, isInteger, isUnsigned, size);
375            }
376          } else {
377            throw new InternalError("\"" + t.sval + "\"");
378          }
379        }
380      } catch (IOException ioe) {
381        ioe.printStackTrace();
382      } finally {
383        try {
384          in.close();
385        } catch (Exception e) {
386        }
387      }
388    }
389  }
390
391  private void readVMStructs() {
392    // Get the variables we need in order to traverse the VMStructEntry[]
393    long structEntryTypeNameOffset;
394    long structEntryFieldNameOffset;
395    long structEntryTypeStringOffset;
396    long structEntryIsStaticOffset;
397    long structEntryOffsetOffset;
398    long structEntryAddressOffset;
399    long structEntryArrayStride;
400
401    structEntryTypeNameOffset     = getLongValueFromProcess("gHotSpotVMStructEntryTypeNameOffset");
402    structEntryFieldNameOffset    = getLongValueFromProcess("gHotSpotVMStructEntryFieldNameOffset");
403    structEntryTypeStringOffset   = getLongValueFromProcess("gHotSpotVMStructEntryTypeStringOffset");
404    structEntryIsStaticOffset     = getLongValueFromProcess("gHotSpotVMStructEntryIsStaticOffset");
405    structEntryOffsetOffset       = getLongValueFromProcess("gHotSpotVMStructEntryOffsetOffset");
406    structEntryAddressOffset      = getLongValueFromProcess("gHotSpotVMStructEntryAddressOffset");
407    structEntryArrayStride        = getLongValueFromProcess("gHotSpotVMStructEntryArrayStride");
408
409    if (structEntryArrayStride == 0L) {
410      throw new RuntimeException("zero stride: cannot read types.");
411    }
412
413    // Fetch the address of the VMStructEntry*
414    Address entryAddr = lookupInProcess("gHotSpotVMStructs");
415    // Dereference this once to get the pointer to the first VMStructEntry
416    entryAddr = entryAddr.getAddressAt(0);
417    if (entryAddr == null) {
418      throw new RuntimeException("gHotSpotVMStructs was not initialized properly in the remote process; can not continue");
419    }
420
421    // Start iterating down it until we find an entry with no name
422    Address fieldNameAddr = null;
423    String typeName = null;
424    String fieldName = null;
425    String typeString = null;
426    boolean isStatic = false;
427    long offset = 0;
428    Address staticFieldAddr = null;
429    long size = 0;
430    long index = 0;
431    String opaqueName = "<opaque>";
432    lookupOrCreateClass(opaqueName, false, false, false);
433
434    do {
435      // Fetch the field name first
436      fieldNameAddr = entryAddr.getAddressAt(structEntryFieldNameOffset);
437      if (fieldNameAddr != null) {
438        fieldName = CStringUtilities.getString(fieldNameAddr);
439
440        // Now the rest of the names. Keep in mind that the type name
441        // may be NULL, indicating that the type is opaque.
442        Address addr = entryAddr.getAddressAt(structEntryTypeNameOffset);
443        if (addr == null) {
444          throw new RuntimeException("gHotSpotVMStructs unexpectedly had a NULL type name at index " + index);
445        }
446        typeName = CStringUtilities.getString(addr);
447
448        addr = entryAddr.getAddressAt(structEntryTypeStringOffset);
449        if (addr == null) {
450          typeString = opaqueName;
451        } else {
452          typeString = CStringUtilities.getString(addr);
453        }
454
455        isStatic = !(entryAddr.getCIntegerAt(structEntryIsStaticOffset, C_INT32_SIZE, false) == 0);
456        if (isStatic) {
457          staticFieldAddr = entryAddr.getAddressAt(structEntryAddressOffset);
458          offset = 0;
459        } else {
460          offset = entryAddr.getCIntegerAt(structEntryOffsetOffset, C_INT64_SIZE, true);
461          staticFieldAddr = null;
462        }
463
464        // The containing Type must already be in the database -- no exceptions
465        BasicType containingType = lookupOrFail(typeName);
466
467        // The field's Type must already be in the database -- no exceptions
468        BasicType fieldType = (BasicType)lookupType(typeString);
469
470        // Create field by type
471        createField(containingType, fieldName, fieldType,
472                    isStatic, offset, staticFieldAddr);
473      }
474
475      ++index;
476      entryAddr = entryAddr.addOffsetTo(structEntryArrayStride);
477    } while (fieldNameAddr != null);
478  }
479
480  private void readVMIntConstants() {
481    // Get the variables we need in order to traverse the VMIntConstantEntry[]
482    long intConstantEntryNameOffset;
483    long intConstantEntryValueOffset;
484    long intConstantEntryArrayStride;
485
486    intConstantEntryNameOffset  = getLongValueFromProcess("gHotSpotVMIntConstantEntryNameOffset");
487    intConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMIntConstantEntryValueOffset");
488    intConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMIntConstantEntryArrayStride");
489
490    if (intConstantEntryArrayStride == 0L) {
491      throw new RuntimeException("zero stride: cannot read types.");
492    }
493
494
495    // Fetch the address of the VMIntConstantEntry*
496    Address entryAddr = lookupInProcess("gHotSpotVMIntConstants");
497    // Dereference this once to get the pointer to the first VMIntConstantEntry
498    entryAddr = entryAddr.getAddressAt(0);
499    if (entryAddr == null) {
500      throw new RuntimeException("gHotSpotVMIntConstants was not initialized properly in the remote process; can not continue");
501    }
502
503    // Start iterating down it until we find an entry with no name
504    Address nameAddr = null;
505    do {
506      // Fetch the type name first
507      nameAddr = entryAddr.getAddressAt(intConstantEntryNameOffset);
508      if (nameAddr != null) {
509        String name = CStringUtilities.getString(nameAddr);
510        int value = (int) entryAddr.getCIntegerAt(intConstantEntryValueOffset, C_INT32_SIZE, false);
511
512        // Be a little resilient
513        Integer oldValue = lookupIntConstant(name, false);
514        if (oldValue == null) {
515          addIntConstant(name, value);
516        } else {
517          if (oldValue.intValue() != value) {
518            throw new RuntimeException("Error: the integer constant \"" + name +
519                                       "\" had its value redefined (old was " + oldValue +
520                                       ", new is " + value + ". Aborting.");
521          } else {
522            System.err.println("Warning: the int constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMIntConstants) " +
523                               "had its value declared as " + value + " twice. Continuing.");
524            duplicateDefCount++;
525          }
526        }
527      }
528
529      entryAddr = entryAddr.addOffsetTo(intConstantEntryArrayStride);
530    } while (nameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS);
531
532    if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) {
533      throw new RuntimeException("too many duplicate definitions");
534    }
535  }
536
537  private void readVMLongConstants() {
538    // Get the variables we need in order to traverse the VMLongConstantEntry[]
539    long longConstantEntryNameOffset;
540    long longConstantEntryValueOffset;
541    long longConstantEntryArrayStride;
542
543    longConstantEntryNameOffset  = getLongValueFromProcess("gHotSpotVMLongConstantEntryNameOffset");
544    longConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMLongConstantEntryValueOffset");
545    longConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMLongConstantEntryArrayStride");
546
547    if (longConstantEntryArrayStride == 0L) {
548      throw new RuntimeException("zero stride: cannot read types.");
549    }
550
551    // Fetch the address of the VMLongConstantEntry*
552    Address entryAddr = lookupInProcess("gHotSpotVMLongConstants");
553    // Dereference this once to get the pointer to the first VMLongConstantEntry
554    entryAddr = entryAddr.getAddressAt(0);
555    if (entryAddr == null) {
556      throw new RuntimeException("gHotSpotVMLongConstants was not initialized properly in the remote process; can not continue");
557    }
558
559    // Start iterating down it until we find an entry with no name
560    Address nameAddr = null;
561    do {
562      // Fetch the type name first
563      nameAddr = entryAddr.getAddressAt(longConstantEntryNameOffset);
564      if (nameAddr != null) {
565        String name = CStringUtilities.getString(nameAddr);
566        int value = (int) entryAddr.getCIntegerAt(longConstantEntryValueOffset, C_INT64_SIZE, true);
567
568        // Be a little resilient
569        Long oldValue = lookupLongConstant(name, false);
570        if (oldValue == null) {
571          addLongConstant(name, value);
572        } else {
573          if (oldValue.longValue() != value) {
574            throw new RuntimeException("Error: the long constant \"" + name +
575                                       "\" had its value redefined (old was " + oldValue +
576                                       ", new is " + value + ". Aborting.");
577          } else {
578            System.err.println("Warning: the long constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMLongConstants) " +
579                               "had its value declared as " + value + " twice. Continuing.");
580            duplicateDefCount++;
581          }
582        }
583      }
584
585      entryAddr = entryAddr.addOffsetTo(longConstantEntryArrayStride);
586    } while (nameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS);
587
588    if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) {
589      throw new RuntimeException("too many duplicate definitions.");
590    }
591  }
592
593  private BasicType lookupOrFail(String typeName) {
594    BasicType type = (BasicType) lookupType(typeName, false);
595    if (type == null) {
596      throw new RuntimeException("Type \"" + typeName + "\", referenced in VMStructs::localHotSpotVMStructs in the remote VM, " +
597                                 "was not present in the remote VMStructs::localHotSpotVMTypes table (should have been caught " +
598                                 "in the debug build of that VM). Can not continue.");
599    }
600    return type;
601  }
602
603  private long getLongValueFromProcess(String symbol) {
604    return lookupInProcess(symbol).getCIntegerAt(0, C_INT64_SIZE, true);
605  }
606
607  private Address lookupInProcess(String symbol) throws NoSuchSymbolException {
608    // FIXME: abstract away the loadobject name
609    for (int i = 0; i < jvmLibNames.length; i++) {
610      Address addr = symbolLookup.lookup(jvmLibNames[i], symbol);
611      if (addr != null) {
612        return addr;
613      }
614    }
615    String errStr = "(";
616    for (int i = 0; i < jvmLibNames.length; i++) {
617      errStr += jvmLibNames[i];
618      if (i < jvmLibNames.length - 1) {
619        errStr += ", ";
620      }
621    }
622    errStr += ")";
623    throw new NoSuchSymbolException(symbol,
624                                    "Could not find symbol \"" + symbol +
625                                    "\" in any of the known library names " +
626                                    errStr);
627  }
628
629  private BasicType lookupOrCreateClass(String typeName, boolean isOopType,
630                                        boolean isIntegerType, boolean isUnsigned) {
631    BasicType type = (BasicType) lookupType(typeName, false);
632    if (type == null) {
633      // Create a new type
634      type = createBasicType(typeName, isOopType, isIntegerType, isUnsigned);
635    }
636    return type;
637  }
638
639  /** Creates a new BasicType, initializes its size to -1 so we can
640      test to ensure that all types' sizes are initialized by VMTypes,
641      and adds it to the database. Takes care of initializing integer
642      and oop types properly. */
643  private BasicType createBasicType(String typeName, boolean isOopType,
644                                    boolean isIntegerType, boolean isUnsigned) {
645
646    BasicType type = null;
647
648    if (isIntegerType) {
649      type = new BasicCIntegerType(this, typeName, isUnsigned);
650    } else {
651      if (typeNameIsPointerType(typeName)) {
652        type = recursiveCreateBasicPointerType(typeName);
653      } else {
654        type = new BasicType(this, typeName);
655      }
656
657      if (isOopType) {
658        // HACK: turn markOop into a C integer type. This allows
659        // proper handling of it in the Serviceability Agent. (FIXME
660        // -- consider doing something different here)
661        if (typeName.equals("markOop")) {
662          type = new BasicCIntegerType(this, typeName, true);
663        } else {
664          type.setIsOopType(true);
665        }
666      }
667    }
668
669    type.setSize(UNINITIALIZED_SIZE);
670    addType(type);
671    return type;
672  }
673
674  /** Recursively creates a PointerType from the string representation
675      of the type's name. Note that this currently needs some
676      workarounds due to incomplete information in the VMStructs
677      database. */
678  private BasicPointerType recursiveCreateBasicPointerType(String typeName) {
679    BasicPointerType result = (BasicPointerType)super.lookupType(typeName, false);
680    if (result != null) {
681      return result;
682    }
683    String targetTypeName = typeName.substring(0, typeName.lastIndexOf('*')).trim();
684    Type targetType = null;
685    if (typeNameIsPointerType(targetTypeName)) {
686      targetType = lookupType(targetTypeName, false);
687      if (targetType == null) {
688        targetType = recursiveCreateBasicPointerType(targetTypeName);
689      }
690    } else {
691      targetType = lookupType(targetTypeName, false);
692      if (targetType == null) {
693        // Workaround for missing C integer types in database.
694        // Also looks like we can't throw an exception for other
695        // missing target types because there are some in old
696        // VMStructs tables that didn't have the target type declared.
697        // For this case, we create basic types that never get filled
698        // in.
699
700        if (targetTypeName.equals("char") ||
701            targetTypeName.equals("const char")) {
702          // We don't have a representation of const-ness of C types in the SA
703          BasicType basicTargetType = createBasicType(targetTypeName, false, true, false);
704          basicTargetType.setSize(1);
705          targetType = basicTargetType;
706        } else if (targetTypeName.equals("u_char")) {
707          BasicType basicTargetType = createBasicType(targetTypeName, false, true, true);
708          basicTargetType.setSize(1);
709          targetType = basicTargetType;
710        } else {
711          if (DEBUG) {
712            System.err.println("WARNING: missing target type \"" + targetTypeName + "\" for pointer type \"" + typeName + "\"");
713          }
714          targetType = createBasicType(targetTypeName, false, false, false);
715        }
716      }
717    }
718    result = new BasicPointerType(this, typeName, targetType);
719    if (pointerSize == UNINITIALIZED_SIZE && !typeName.equals("void*")) {
720      // void* must be declared early so that other pointer types can use that to set their size.
721      throw new InternalError("void* type hasn't been seen when parsing " + typeName);
722    }
723    result.setSize(pointerSize);
724    addType(result);
725    return result;
726  }
727
728  private boolean typeNameIsPointerType(String typeName) {
729    int i = typeName.length() - 1;
730    while (i >= 0 && Character.isWhitespace(typeName.charAt(i))) {
731      --i;
732    }
733    if (i >= 0 && typeName.charAt(i) == '*') {
734      return true;
735    }
736    return false;
737  }
738
739    public void createType(String typeName, String superclassName,
740                           boolean isOopType, boolean isIntegerType,
741                           boolean isUnsigned, long size) {
742        // See whether we have a superclass
743        BasicType superclass = null;
744        if (superclassName != null) {
745            // Fetch or create it (FIXME: would get oop types wrong if
746            // they had a hierarchy; consider using lookupOrFail)
747            superclass = lookupOrCreateClass(superclassName, false, false, false);
748        }
749
750        // Lookup or create the current type
751        BasicType curType = lookupOrCreateClass(typeName, isOopType, isIntegerType, isUnsigned);
752        // Set superclass and/or ensure it's correct
753        if (superclass != null) {
754            if (curType.getSuperclass() == null) {
755                // Set the superclass in the current type
756                curType.setSuperclass(superclass);
757            }
758
759            if (curType.getSuperclass() != superclass) {
760                throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
761                                           "had its superclass redefined (old was " + curType.getSuperclass().getName() + ", new is " +
762                                           superclass.getName() + ").");
763            }
764        }
765
766        // Classes are created with a size of UNINITIALIZED_SIZE.
767        // Set size if necessary.
768        if (curType.getSize() == UNINITIALIZED_SIZE || curType.getSize() == 0) {
769            curType.setSize(size);
770        } else {
771            if (curType.getSize() != size) {
772                throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
773                                           "had its size redefined (old was " + curType.getSize() + ", new is " + size + ").");
774            }
775
776            if (!typeNameIsPointerType(typeName)) {
777                System.err.println("Warning: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " +
778                                   "had its size declared as " + size + " twice. Continuing.");
779                duplicateDefCount++;
780            }
781        }
782
783    }
784
785    /** "Virtual constructor" for fields based on type */
786    public void createField(BasicType containingType,
787                            String name, Type type, boolean isStatic,
788                            long offset, Address staticFieldAddress) {
789        // Add field to containing type
790        containingType.addField(internalCreateField(containingType, name, type, isStatic, offset, staticFieldAddress));
791    }
792
793    Field internalCreateField(BasicType containingType,
794                              String name, Type type, boolean isStatic,
795                              long offset, Address staticFieldAddress) {
796    // "Virtual constructor" based on type
797    if (type.isOopType()) {
798      return new BasicOopField(this, containingType, name, type,
799                               isStatic, offset, staticFieldAddress);
800    }
801
802    if (type instanceof CIntegerType) {
803      return new BasicCIntegerField(this, containingType, name, type,
804                                    isStatic, offset, staticFieldAddress);
805    }
806
807    if (type.equals(getJBooleanType())) {
808      return new BasicJBooleanField(this, containingType, name, type,
809                                    isStatic, offset, staticFieldAddress);
810    }
811
812    if (type.equals(getJByteType())) {
813      return new BasicJByteField(this, containingType, name, type,
814                                 isStatic, offset, staticFieldAddress);
815    }
816
817    if (type.equals(getJCharType())) {
818      return new BasicJCharField(this, containingType, name, type,
819                                 isStatic, offset, staticFieldAddress);
820    }
821
822    if (type.equals(getJDoubleType())) {
823      return new BasicJDoubleField(this, containingType, name, type,
824                                   isStatic, offset, staticFieldAddress);
825    }
826
827    if (type.equals(getJFloatType())) {
828      return new BasicJFloatField(this, containingType, name, type,
829                                  isStatic, offset, staticFieldAddress);
830    }
831
832    if (type.equals(getJIntType())) {
833      return new BasicJIntField(this, containingType, name, type,
834                                isStatic, offset, staticFieldAddress);
835    }
836
837    if (type.equals(getJLongType())) {
838      return new BasicJLongField(this, containingType, name, type,
839                                 isStatic, offset, staticFieldAddress);
840    }
841
842    if (type.equals(getJShortType())) {
843      return new BasicJShortField(this, containingType, name, type,
844                                  isStatic, offset, staticFieldAddress);
845    }
846
847    // Unknown ("opaque") type. Instantiate ordinary Field.
848    return new BasicField(this, containingType, name, type,
849                          isStatic, offset, staticFieldAddress);
850  }
851
852  // For debugging
853  private void dumpMemory(Address addr, int len) {
854    int i = 0;
855    while (i < len) {
856      System.err.print(addr.addOffsetTo(i) + ":");
857      for (int j = 0; j < 8 && i < len; i++, j++) {
858        String s = Long.toHexString(addr.getCIntegerAt(i, 1, true));
859        System.err.print(" 0x");
860        for (int k = 0; k < 2 - s.length(); k++) {
861          System.err.print("0");
862        }
863        System.err.print(s);
864      }
865      System.err.println();
866    }
867  }
868}
869