1 /* ClassWrapper.java - wrap ASM class objects
2 Copyright (C) 2006, 2007 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.classpath.tools.javah;
41 import java.io.ByteArrayOutputStream;
42 import java.io.IOException;
43 import java.io.PrintStream;
44 import java.lang.reflect.Modifier;
45 import java.util.ArrayList;
46 import java.util.HashMap;
47 import java.util.HashSet;
48 import java.util.Iterator;
50 import org.objectweb.asm.tree.ClassNode;
51 import org.objectweb.asm.tree.FieldNode;
52 import org.objectweb.asm.tree.MethodNode;
54 public class ClassWrapper
59 ClassWrapper superClass;
61 ArrayList interfaceClasses;
63 // The virtual table for this class.
66 // A set of all the bridge method targets we've found.
67 HashSet bridgeTargets;
69 // A set of all the method names in this class.
70 HashSet methodNames = new HashSet();
72 // This maps a method name + descriptor, e.g. "method()V", to the
73 // name chosen for the method. This is used when computing the
74 // names of bridge method targets.
75 HashMap methodNameMap = new HashMap();
77 public ClassWrapper(Main classpath)
79 this.classpath = classpath;
82 public boolean hasNativeMethod()
84 Iterator i = methods.iterator();
87 MethodNode method = (MethodNode) i.next();
88 if (Modifier.isNative(method.access))
94 public boolean isThrowable() throws IOException
97 ClassWrapper self = this;
100 if (self.name.equals("java/lang/Throwable"))
102 self = self.superClass;
107 private void linkSupers() throws IOException
109 if (superName == null)
111 // Object, do nothing.
114 if (superClass == null)
116 superClass = classpath.getClass(superName);
117 assert interfaceClasses == null;
118 interfaceClasses = new ArrayList();
119 for (int i = 0; i < interfaces.size(); ++i)
121 String ifname = (String) interfaces.get(i);
122 ClassWrapper iface = classpath.getClass(ifname);
124 interfaceClasses.add(iface);
127 superClass.linkSupers();
130 private int findSlot(MethodNode method)
132 for (int i = vtable.size() - 1; i >= 0; --i)
134 MethodNode base = (MethodNode) vtable.get(i);
135 if (MethodHelper.overrides(method, base))
141 private void addInterfaceMethods(ClassWrapper iface)
143 Iterator i = iface.methods.iterator();
146 MethodNode im = (MethodNode) i.next();
147 int slot = findSlot(im);
151 // Also add it to our local methods.
155 addInterfaces(iface);
158 private void addInterfaces(ClassWrapper base)
160 if (base.interfaceClasses == null)
162 Iterator i = base.interfaceClasses.iterator();
165 ClassWrapper iface = (ClassWrapper) i.next();
166 addInterfaceMethods(iface);
170 private void addLocalMethods()
172 Iterator i = methods.iterator();
175 MethodNode meth = (MethodNode) i.next();
176 methodNames.add(meth.name);
177 if (Modifier.isStatic(meth.access))
179 int slot = findSlot(meth);
183 vtable.set(slot, meth);
187 private void makeVtable() throws IOException
191 if (superClass != null)
193 superClass.makeVtable();
194 vtable = new ArrayList(superClass.vtable);
195 bridgeTargets = new HashSet(superClass.bridgeTargets);
196 methodNameMap = new HashMap(superClass.methodNameMap);
201 vtable = new ArrayList();
202 bridgeTargets = new HashSet();
203 methodNameMap = new HashMap();
208 // Make a set of all the targets of bridge methods. We rename
209 // bridge target methods to avoid problems with C++. You might
210 // think we could rename the bridge methods themselves, but bridge
211 // methods by definition override a method from the superclass --
212 // and we have to consider the superclass' header as an
213 // unchangeable entity.
214 Iterator i = methods.iterator();
217 MethodNode m = (MethodNode) i.next();
218 String desc = MethodHelper.getBridgeTarget(m);
221 String sum = m.name + desc;
222 boolean newTarget = bridgeTargets.add(sum);
225 // Bridge target that is new in this class.
226 String cname = this.name;
227 int index = cname.lastIndexOf('/');
228 cname = cname.substring(index + 1);
229 methodNameMap.put(sum, cname + "$" + m.name);
235 private void printFields(CniPrintStream out)
237 Iterator i = fields.iterator();
238 ClassWrapper self = superClass;
241 FieldNode f = (FieldNode) i.next();
242 boolean hasMethodName = methodNames.contains(f.name);
243 if (FieldHelper.print(out, f, self, hasMethodName))
248 private void printMethods(CniPrintStream out) throws IOException
252 // A given method is either static, overrides a super method, or
253 // is already in vtable order.
254 Iterator i = methods.iterator();
257 MethodNode m = (MethodNode) i.next();
259 String sum = m.name + m.desc;
260 if (bridgeTargets.contains(sum))
261 nameToUse = (String) methodNameMap.get(sum);
263 nameToUse = Keywords.getCxxName(m.name);
264 methodNameMap.put(sum, nameToUse);
265 MethodHelper.print(out, m, this, nameToUse);
269 private void printTextList(PrintStream out, int what, ArrayList textList)
271 if (textList == null)
273 Iterator i = textList.iterator();
274 boolean first = true;
277 Text item = (Text) i.next();
278 if (item.type == what)
285 if (what == Text.FRIEND)
286 out.print(" friend ");
287 out.println(item.text);
292 public void print(CniPrintStream out)
294 out.print("::" + name.replaceAll("/", "::"));
297 // This prints the body of a class to a CxxPrintStream.
298 private void printContents(CniPrintStream out, ArrayList textList)
301 printTextList(out, Text.PREPEND, textList);
305 // Don't use our print() -- we don't want the leading "::".
306 out.print(name.replaceAll("/", "::"));
307 if (superClass != null)
309 out.print(" : public ");
310 superClass.print(out);
315 printTextList(out, Text.ADD, textList);
318 // Note: methods must come first, as we build the list
319 // of method names while printing them.
323 out.setModifiers(Modifier.PUBLIC);
324 out.println(" static ::java::lang::Class class$;");
326 printTextList(out, Text.FRIEND, textList);
329 if (Modifier.isInterface(access))
330 out.print(" __attribute__ ((java_interface))");
333 printTextList(out, Text.APPEND, textList);
336 public void printFully(PrintStream out) throws IOException
340 ArrayList textList = classpath.getClassTextList(name);
342 out.println("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-");
344 String xname = "__" + name.replaceAll("/", "_") + "__";
345 out.println("#ifndef " + xname);
346 out.println("#define " + xname);
348 out.println("#pragma interface");
351 if (superClass != null)
353 out.print("#include <");
354 out.print(superName);
358 // Write the body of the stream here. This lets
359 // us emit the namespaces without a second pass.
360 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
361 CniPrintStream cxxOut = new CniPrintStream(bytes);
362 cxxOut.addClass(this);
363 printContents(cxxOut, textList);
364 cxxOut.printNamespaces(out);
368 out.println("#endif // " + xname);
371 public String toString()