1/*
2 * Copyright (c) 2000, 2008, 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.types.basic;
26
27import java.util.*;
28import sun.jvm.hotspot.debugger.*;
29import sun.jvm.hotspot.types.*;
30import sun.jvm.hotspot.utilities.*;
31
32/** <P> This is a basic implementation of the Type interface which
33    should be complete enough to be portable across platforms. The
34    only issue will be the construction of these objects and their
35    components from the platform-specific debugging information; see
36    BasicTypeDataBase. </P>
37
38    <P> There are two types of clients of this class. The first is
39    that which builds the TypeDatabase. This kind of client uses the
40    additional public methods beyond those in the Type interface to
41    properly configure the BasicType objects. The second is the
42    consumer of these types; this kind of client should deal only with
43    the Type interfaces. </P> */
44
45public class BasicType implements Type {
46  protected BasicTypeDataBase db;
47
48  private String name;
49  private long size;
50  private boolean isJavaPrimitiveType;
51  private boolean isOopType;
52  // These are only the fields defined in this class, not any of this
53  // class's superclasses.
54  private Map nameToFieldMap = new HashMap();
55  private List fieldList = new LinkedList();
56  // Superclass, or null if none. Primitive types do not have any
57  // inheritance relationship.
58  private Type superclass;
59
60  /** superclass may be null */
61  public BasicType(BasicTypeDataBase db, String name, Type superclass) {
62    if (name == null) {
63      throw new IllegalArgumentException("name may not be null");
64    }
65    this.db = db;
66    this.name = name;
67    this.superclass = superclass;
68  }
69
70  /** Equivalent to BasicType(db, name, null) */
71  public BasicType(BasicTypeDataBase db, String name) {
72    this(db, name, null);
73  }
74
75  public boolean equals(Object obj) {
76    if (obj == null) {
77      return false;
78    }
79
80    if (!(obj instanceof BasicType)) {
81      return false;
82    }
83
84    BasicType arg = (BasicType) obj;
85
86    if (!name.equals(arg.name)) {
87      return false;
88    }
89
90    return true;
91  }
92
93  public int hashCode() {
94    return name.hashCode();
95  }
96
97  public String toString() {
98    return name;
99  }
100
101  public String getName() {
102    return name;
103  }
104
105  /** This should only be called at most once, and only by the builder
106      of the type database */
107  public void setSuperclass(Type superclass) {
108    this.superclass = superclass;
109  }
110
111  public Type getSuperclass() {
112    return superclass;
113  }
114
115  /** This should only be called at most once, and only by the builder
116      of the type database */
117  public void setSize(long sizeInBytes) {
118    this.size = sizeInBytes;
119  }
120
121  public long getSize() {
122    return size;
123  }
124
125  /** Overridden by BasicCIntegerType */
126  public boolean isCIntegerType() {
127    return false;
128  }
129
130  public boolean isCStringType() {
131    if (isPointerType()) {
132      Type target = ((PointerType)this).getTargetType();
133      return target.isCIntegerType() &&
134             target.getName().equals("const char");
135    } else {
136      return false;
137    }
138  }
139
140  public boolean isJavaPrimitiveType() {
141    return isJavaPrimitiveType;
142  }
143
144  /** This should only be called at most once, and only by the builder
145      of the type database */
146  public void setIsJavaPrimitiveType(boolean isJavaPrimitiveType) {
147    this.isJavaPrimitiveType = isJavaPrimitiveType;
148  }
149
150  public boolean isOopType() {
151    return isOopType;
152  }
153
154  /** Overridden by BasicPointerType */
155  public boolean isPointerType() {
156    return false;
157  }
158
159  /** This should only be called at most once, and only by the builder
160      of the type database */
161  public void setIsOopType(boolean isOopType) {
162    this.isOopType = isOopType;
163  }
164
165  public Field getField(String fieldName, boolean searchSuperclassFields,
166                        boolean throwExceptionIfNotFound) {
167    Field field = null;
168    if (nameToFieldMap != null) {
169      field = (Field) nameToFieldMap.get(fieldName);
170
171      if (field != null) {
172        return field;
173      }
174    }
175
176    if (searchSuperclassFields) {
177      if (superclass != null) {
178        field = superclass.getField(fieldName, searchSuperclassFields, false);
179      }
180    }
181
182    if (field == null && throwExceptionIfNotFound) {
183      throw new RuntimeException("field \"" + fieldName + "\" not found in type " + name);
184    }
185
186    return field;
187  }
188
189  public Field getField(String fieldName, boolean searchSuperclassFields) {
190    return getField(fieldName, searchSuperclassFields, true);
191  }
192
193  public Field getField(String fieldName) {
194    return getField(fieldName, true);
195  }
196
197  public Field getField(String fieldName, Type declaredType,
198                        boolean searchSuperclassFields) throws WrongTypeException {
199    Field res = getField(fieldName, searchSuperclassFields);
200    if (res == null) {
201      return null;
202    }
203    if (!res.getType().equals(declaredType)) {
204      throw new WrongTypeException("field \"" + fieldName + "\" in type " + name +
205                                    " is not of type " + declaredType +
206                                    ", but instead of type " + res.getType());
207    }
208    return res;
209  }
210
211  public Field getField(String fieldName, Type declaredType) throws WrongTypeException {
212    return getField(fieldName, declaredType, false);
213  }
214
215  /** The returned iterator's "remove" method must not be called */
216  public Iterator getFields() {
217    return new ConstIterator(fieldList.iterator());
218  }
219
220  //--------------------------------------------------------------------------------
221  // Specialized field type accessors
222  //
223
224  public JBooleanField getJBooleanField(String fieldName) throws WrongTypeException {
225    return (JBooleanField) getField(fieldName, db.getJBooleanType());
226  }
227
228  public JByteField    getJByteField(String fieldName) throws WrongTypeException {
229    return (JByteField) getField(fieldName, db.getJByteType());
230  }
231
232  public JCharField    getJCharField(String fieldName) throws WrongTypeException {
233    return (JCharField) getField(fieldName, db.getJCharType());
234  }
235
236  public JDoubleField  getJDoubleField(String fieldName) throws WrongTypeException {
237    return (JDoubleField) getField(fieldName, db.getJDoubleType());
238  }
239
240  public JFloatField   getJFloatField(String fieldName) throws WrongTypeException {
241    return (JFloatField) getField(fieldName, db.getJFloatType());
242  }
243
244  public JIntField     getJIntField(String fieldName) throws WrongTypeException {
245    return (JIntField) getField(fieldName, db.getJIntType());
246  }
247
248  public JLongField    getJLongField(String fieldName) throws WrongTypeException {
249    return (JLongField) getField(fieldName, db.getJLongType());
250  }
251
252  public JShortField   getJShortField(String fieldName) throws WrongTypeException {
253    return (JShortField) getField(fieldName, db.getJShortType());
254  }
255
256  public CIntegerField getCIntegerField(String fieldName) throws WrongTypeException {
257    Field field = getField(fieldName);
258    if (!(field.getType() instanceof CIntegerType)) {
259      throw new WrongTypeException("field \"" + fieldName + "\" in type " + name +
260                                   " is not of C integer type, but instead of type " +
261                                   field.getType());
262    }
263    return (CIntegerField) field;
264  }
265
266  public OopField getOopField(String fieldName) throws WrongTypeException {
267    Field field = getField(fieldName);
268    if (!field.getType().isOopType()) {
269      throw new WrongTypeException("field \"" + fieldName + "\" in type " + name +
270                                   " is not of oop type, but instead of type " +
271                                   field.getType());
272    }
273    return (OopField) field;
274  }
275
276  public NarrowOopField getNarrowOopField(String fieldName) throws WrongTypeException {
277    return (NarrowOopField) new BasicNarrowOopField(getOopField(fieldName));
278  }
279
280  public AddressField getAddressField(String fieldName) {
281    // This type can not be inferred (for now), so provide a wrapper
282    Field field = getField(fieldName);
283    if (field == null) {
284      return null;
285    }
286    return new BasicAddressFieldWrapper(field);
287  }
288
289  /** This method should only be used by the builder of the
290      TypeDataBase. Throws a RuntimeException if a field with this
291      name was already present in this class. */
292  public void addField(Field field) {
293    if (nameToFieldMap.get(field.getName()) != null) {
294      throw new RuntimeException("field of name \"" + field.getName() + "\" already present in type " + this);
295    }
296
297    nameToFieldMap.put(field.getName(), field);
298    fieldList.add(field);
299  }
300
301  /** This method should only be used by the builder of the
302      TypeDataBase. Throws a RuntimeException if a field with this
303      name was not present in this class. */
304  public void removeField(Field field) {
305    if (nameToFieldMap.remove(field.getName()) == null) {
306      throw new RuntimeException("field of name \"" + field.getName() + "\" was not present");
307    }
308    fieldList.remove(field);
309  }
310}
311