OSDN Git Service

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