OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / tools / gnu / classpath / tools / javah / ClassWrapper.java
1 /* ClassWrapper.java - wrap ASM class objects
2  Copyright (C) 2006 Free Software Foundation, Inc.
3
4  This file is part of GNU Classpath.
5
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)
9  any later version.
10
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.
15
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
19  02110-1301 USA.
20
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
24  combination.
25
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. */
37
38
39 package gnu.classpath.tools.javah;
40
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.HashSet;
47 import java.util.Iterator;
48
49 import org.objectweb.asm.tree.ClassNode;
50 import org.objectweb.asm.tree.FieldNode;
51 import org.objectweb.asm.tree.MethodNode;
52
53 public class ClassWrapper
54     extends ClassNode
55 {
56   Main classpath;
57
58   ClassWrapper superClass;
59
60   ArrayList interfaceClasses;
61
62   // The virtual table for this class.
63   ArrayList vtable;
64
65   // A set of all the bridge method targets we've found.
66   HashSet bridgeTargets;
67
68   // A set of all the method names in this class.
69   HashSet methodNames = new HashSet();
70
71   public ClassWrapper(Main classpath)
72   {
73     this.classpath = classpath;
74   }
75
76   public boolean hasNativeMethod()
77   {
78     Iterator i = methods.iterator();
79     while (i.hasNext())
80       {
81         MethodNode method = (MethodNode) i.next();
82         if (Modifier.isNative(method.access))
83           return true;
84       }
85     return false;
86   }
87
88   public boolean isThrowable() throws IOException
89   {
90     linkSupers();
91     ClassWrapper self = this;
92     while (self != null)
93       {
94         if (self.name.equals("java/lang/Throwable"))
95           return true;
96         self = self.superClass;
97       }
98     return false;
99   }
100
101   private void linkSupers() throws IOException
102   {
103     if (superName == null)
104       {
105         // Object, do nothing.
106         return;
107       }
108     if (superClass == null)
109       {
110         superClass = classpath.getClass(superName);
111         assert interfaceClasses == null;
112         interfaceClasses = new ArrayList();
113         for (int i = 0; i < interfaces.size(); ++i)
114           {
115             String ifname = (String) interfaces.get(i);
116             ClassWrapper iface = classpath.getClass(ifname);
117             iface.linkSupers();
118             interfaceClasses.add(iface);
119           }
120       }
121     superClass.linkSupers();
122   }
123
124   private int findSlot(MethodNode method)
125   {
126     for (int i = vtable.size() - 1; i >= 0; --i)
127       {
128         MethodNode base = (MethodNode) vtable.get(i);
129         if (MethodHelper.overrides(method, base))
130           return i;
131       }
132     return - 1;
133   }
134
135   private void addInterfaceMethods(ClassWrapper iface)
136   {
137     Iterator i = iface.methods.iterator();
138     while (i.hasNext())
139       {
140         MethodNode im = (MethodNode) i.next();
141         int slot = findSlot(im);
142         if (slot == - 1)
143           {
144             vtable.add(im);
145             // Also add it to our local methods.
146             methods.add(im);
147           }
148       }
149     addInterfaces(iface);
150   }
151
152   private void addInterfaces(ClassWrapper base)
153   {
154     if (base.interfaceClasses == null)
155       return;
156     Iterator i = base.interfaceClasses.iterator();
157     while (i.hasNext())
158       {
159         ClassWrapper iface = (ClassWrapper) i.next();
160         addInterfaceMethods(iface);
161       }
162   }
163
164   private void addLocalMethods()
165   {
166     Iterator i = methods.iterator();
167     while (i.hasNext())
168       {
169         MethodNode meth = (MethodNode) i.next();
170         methodNames.add(meth.name);
171         if (Modifier.isStatic(meth.access))
172           continue;
173         int slot = findSlot(meth);
174         if (slot == - 1)
175           vtable.add(meth);
176         else
177           vtable.set(slot, meth);
178       }
179   }
180
181   private void makeVtable() throws IOException
182   {
183     if (vtable != null)
184       return;
185     if (superClass != null)
186       {
187         superClass.makeVtable();
188         vtable = new ArrayList(superClass.vtable);
189         bridgeTargets = new HashSet(superClass.bridgeTargets);
190       }
191     else
192       {
193         // Object.
194         vtable = new ArrayList();
195         bridgeTargets = new HashSet();
196       }
197     addLocalMethods();
198     addInterfaces(this);
199
200     // Make a set of all the targets of bridge methods.
201     // We rename bridge methods to avoid problems with C++.
202     Iterator i = methods.iterator();
203     while (i.hasNext())
204       {
205         MethodNode m = (MethodNode) i.next();
206         String desc = MethodHelper.getBridgeTarget(m);
207         if (desc != null)
208           bridgeTargets.add(m.name + desc);
209       }
210   }
211
212   private void printFields(CniPrintStream out)
213   {
214     Iterator i = fields.iterator();
215     ClassWrapper self = superClass;
216     while (i.hasNext())
217       {
218         FieldNode f = (FieldNode) i.next();
219         boolean hasMethodName = methodNames.contains(f.name);
220         if (FieldHelper.print(out, f, self, hasMethodName))
221           self = null;
222       }
223   }
224
225   private void printMethods(CniPrintStream out) throws IOException
226   {
227     makeVtable();
228
229     // A given method is either static, overrides a super method, or
230     // is already in vtable order.
231     Iterator i = methods.iterator();
232     while (i.hasNext())
233       {
234         MethodNode m = (MethodNode) i.next();
235         boolean isTarget = bridgeTargets.contains(m.name + m.desc);
236         MethodHelper.print(out, m, this, isTarget);
237       }
238   }
239
240   private void printTextList(PrintStream out, int what, ArrayList textList)
241   {
242     if (textList == null)
243       return;
244     Iterator i = textList.iterator();
245     boolean first = true;
246     while (i.hasNext())
247       {
248         Text item = (Text) i.next();
249         if (item.type == what)
250           {
251             if (first)
252               {
253                 out.println();
254                 first = false;
255               }
256             if (what == Text.FRIEND)
257               out.print("  friend ");
258             out.println(item.text);
259           }
260       }
261   }
262
263   public void print(CniPrintStream out)
264   {
265     out.print("::" + name.replaceAll("/", "::"));
266   }
267
268   // This prints the body of a class to a CxxPrintStream.
269   private void printContents(CniPrintStream out, ArrayList textList)
270       throws IOException
271   {
272     printTextList(out, Text.PREPEND, textList);
273     out.println();
274
275     out.print("class ");
276     // Don't use our print() -- we don't want the leading "::".
277     out.print(name.replaceAll("/", "::"));
278     if (superClass != null)
279       {
280         out.print(" : public ");
281         superClass.print(out);
282       }
283     out.println();
284     out.println("{");
285
286     printTextList(out, Text.ADD, textList);
287     out.println();
288
289     // Note: methods must come first, as we build the list
290     // of method names while printing them.
291     printMethods(out);
292     printFields(out);
293
294     out.setModifiers(Modifier.PUBLIC);
295     out.println("  static ::java::lang::Class class$;");
296
297     printTextList(out, Text.FRIEND, textList);
298
299     out.print("}");
300     if (Modifier.isInterface(access))
301       out.print(" __attribute__ ((java_interface))");
302     out.println(";");
303
304     printTextList(out, Text.APPEND, textList);
305   }
306
307   public void printFully(PrintStream out) throws IOException
308   {
309     linkSupers();
310
311     ArrayList textList = classpath.getClassTextList(name);
312
313     out.println("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-");
314     out.println();
315     String xname = "__" + name.replaceAll("/", "_") + "__";
316     out.println("#ifndef " + xname);
317     out.println("#define " + xname);
318     out.println();
319     out.println("#pragma interface");
320     out.println();
321
322     if (superClass != null)
323       {
324         out.print("#include <");
325         out.print(superName);
326         out.println(".h>");
327       }
328
329     // Write the body of the stream here. This lets
330     // us emit the namespaces without a second pass.
331     ByteArrayOutputStream bytes = new ByteArrayOutputStream();
332     CniPrintStream cxxOut = new CniPrintStream(bytes);
333     cxxOut.addClass(this);
334     printContents(cxxOut, textList);
335     cxxOut.printNamespaces(out);
336     bytes.writeTo(out);
337
338     out.println();
339     out.println("#endif // " + xname);
340   }
341
342   public String toString()
343   {
344     return name;
345   }
346 }