diff options
author | Tom Tromey <tromey@redhat.com> | 2006-07-28 15:22:29 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2006-07-28 15:22:29 +0000 |
commit | 1df72fb152a2ed319bfe12ae18c3a558e3b12d53 (patch) | |
tree | a50a023bd8c959cb589a5a687269c700b1392da3 /tools/gnu/classpath | |
parent | b169e48309762b3f1d3f2a26976968a581e5c7bf (diff) | |
download | classpath-1df72fb152a2ed319bfe12ae18c3a558e3b12d53.tar.gz |
* NEWS: Updated.
* .classpath: Updated.
* tools/.cvsignore: Added gjavah.
* tools/Makefile.am ($(TOOLS_ZIP)): Only build javah if ASM is
available.
(GLIBJ_CLASSPATH): Add asm jar.
(javah): New macro.
(bin_PROGRAMS, bin_SCRIPTS): Added $(javah).
(gjavah_SOURCES, gjavah_CFLAGS, gjavah_LDFLAGS): new macros.
* tools/gjavah.in: New file.
* configure.ac: Added --with-asm option.
* tools/gnu/classpath/tools/javah/ClassWrapper.java: New file.
* tools/gnu/classpath/tools/javah/CniIncludePrinter.java: Likewise.
* tools/gnu/classpath/tools/javah/CniPrintStream.java: Likewise.
* tools/gnu/classpath/tools/javah/CniStubPrinter.java: Likewise.
* tools/gnu/classpath/tools/javah/FieldHelper.java: Likewise.
* tools/gnu/classpath/tools/javah/JniHelper.java: Likewise.
* tools/gnu/classpath/tools/javah/JniIncludePrinter.java: Likewise.
* tools/gnu/classpath/tools/javah/JniStubPrinter.java: Likewise.
* tools/gnu/classpath/tools/javah/Keywords.java: Likewise.
* tools/gnu/classpath/tools/javah/Main.java: Likewise.
* tools/gnu/classpath/tools/javah/MethodHelper.java: Likewise.
* tools/gnu/classpath/tools/javah/PackageWrapper.java: Likewise.
* tools/gnu/classpath/tools/javah/PathOptionGroup.java: Likewise.
* tools/gnu/classpath/tools/javah/Printer.java: Likewise.
* tools/gnu/classpath/tools/javah/Text.java: Likewise.
Diffstat (limited to 'tools/gnu/classpath')
-rw-r--r-- | tools/gnu/classpath/tools/javah/ClassWrapper.java | 341 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/CniIncludePrinter.java | 69 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/CniPrintStream.java | 243 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/CniStubPrinter.java | 119 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/FieldHelper.java | 97 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/JniHelper.java | 120 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/JniIncludePrinter.java | 144 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/JniPrintStream.java | 115 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/JniStubPrinter.java | 98 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/Keywords.java | 85 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/Main.java | 375 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/MethodHelper.java | 130 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/PackageWrapper.java | 54 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/PathOptionGroup.java | 135 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/Printer.java | 55 | ||||
-rw-r--r-- | tools/gnu/classpath/tools/javah/Text.java | 60 |
16 files changed, 2240 insertions, 0 deletions
diff --git a/tools/gnu/classpath/tools/javah/ClassWrapper.java b/tools/gnu/classpath/tools/javah/ClassWrapper.java new file mode 100644 index 000000000..778896395 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/ClassWrapper.java @@ -0,0 +1,341 @@ +/* ClassWrapper.java - wrap ASM class objects + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public class ClassWrapper + extends ClassNode +{ + Main classpath; + + ClassWrapper superClass; + + ArrayList interfaceClasses; + + // The virtual table for this class. + ArrayList vtable; + + // A set of all the bridge method targets we've found. + HashSet bridgeTargets; + + // A set of all the method names in this class. + HashSet methodNames = new HashSet(); + + public ClassWrapper(Main classpath) + { + this.classpath = classpath; + } + + public boolean hasNativeMethod() + { + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (Modifier.isNative(method.access)) + return true; + } + return false; + } + + public boolean isThrowable() throws IOException + { + linkSupers(); + ClassWrapper self = this; + while (self != null) + { + if (self.name.equals("java/lang/Throwable")) + return true; + self = self.superClass; + } + return false; + } + + private void linkSupers() throws IOException + { + if (superName == null) + { + // Object, do nothing. + return; + } + if (superClass == null) + { + superClass = classpath.getClass(superName); + assert interfaceClasses == null; + interfaceClasses = new ArrayList(); + for (int i = 0; i < interfaces.size(); ++i) + { + String ifname = (String) interfaces.get(i); + ClassWrapper iface = classpath.getClass(ifname); + iface.linkSupers(); + interfaceClasses.add(iface); + } + } + superClass.linkSupers(); + } + + private int findSlot(MethodNode method) + { + for (int i = vtable.size() - 1; i >= 0; --i) + { + MethodNode base = (MethodNode) vtable.get(i); + if (MethodHelper.overrides(method, base)) + return i; + } + return - 1; + } + + private void addInterfaceMethods(ClassWrapper iface) + { + Iterator i = iface.methods.iterator(); + while (i.hasNext()) + { + MethodNode im = (MethodNode) i.next(); + int slot = findSlot(im); + if (slot == - 1) + { + vtable.add(im); + // Also add it to our local methods. + methods.add(im); + } + } + addInterfaces(iface); + } + + private void addInterfaces(ClassWrapper base) + { + if (base.interfaceClasses == null) + return; + Iterator i = base.interfaceClasses.iterator(); + while (i.hasNext()) + { + ClassWrapper iface = (ClassWrapper) i.next(); + addInterfaceMethods(iface); + } + } + + private void addLocalMethods() + { + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode meth = (MethodNode) i.next(); + methodNames.add(meth.name); + if (Modifier.isStatic(meth.access)) + continue; + int slot = findSlot(meth); + if (slot == - 1) + vtable.add(meth); + else + vtable.set(slot, meth); + } + } + + private void makeVtable() throws IOException + { + if (vtable != null) + return; + if (superClass != null) + { + superClass.makeVtable(); + vtable = new ArrayList(superClass.vtable); + bridgeTargets = new HashSet(superClass.bridgeTargets); + } + else + { + // Object. + vtable = new ArrayList(); + bridgeTargets = new HashSet(); + } + addLocalMethods(); + addInterfaces(this); + + // Make a set of all the targets of bridge methods. + // We rename bridge methods to avoid problems with C++. + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode m = (MethodNode) i.next(); + String desc = MethodHelper.getBridgeTarget(m); + if (desc != null) + bridgeTargets.add(m.name + desc); + } + } + + private void printFields(CniPrintStream out) + { + Iterator i = fields.iterator(); + ClassWrapper self = superClass; + while (i.hasNext()) + { + FieldNode f = (FieldNode) i.next(); + boolean hasMethodName = methodNames.contains(f.name); + if (FieldHelper.print(out, f, self, hasMethodName)) + self = null; + } + } + + private void printMethods(CniPrintStream out) throws IOException + { + makeVtable(); + + // A given method is either static, overrides a super method, or + // is already in vtable order. + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode m = (MethodNode) i.next(); + boolean isTarget = bridgeTargets.contains(m.name + m.desc); + MethodHelper.print(out, m, this, isTarget); + } + } + + private void printTextList(PrintStream out, int what, ArrayList textList) + { + if (textList == null) + return; + Iterator i = textList.iterator(); + boolean first = true; + while (i.hasNext()) + { + Text item = (Text) i.next(); + if (item.type == what) + { + if (first) + { + out.println(); + first = false; + } + if (what == Text.FRIEND) + out.print(" friend "); + out.println(item.text); + } + } + } + + public void print(CniPrintStream out) + { + out.print("::" + name.replaceAll("/", "::")); + } + + // This prints the body of a class to a CxxPrintStream. + private void printContents(CniPrintStream out, ArrayList textList) + throws IOException + { + printTextList(out, Text.PREPEND, textList); + out.println(); + + out.print("class "); + // Don't use our print() -- we don't want the leading "::". + out.print(name.replaceAll("/", "::")); + if (superClass != null) + { + out.print(" : public "); + superClass.print(out); + } + out.println(); + out.println("{"); + + printTextList(out, Text.ADD, textList); + out.println(); + + // Note: methods must come first, as we build the list + // of method names while printing them. + printMethods(out); + printFields(out); + + out.setModifiers(Modifier.PUBLIC); + out.println(" static ::java::lang::Class class$;"); + + printTextList(out, Text.FRIEND, textList); + + out.print("}"); + if (Modifier.isInterface(access)) + out.print(" __attribute__ ((java_interface))"); + out.println(";"); + + printTextList(out, Text.APPEND, textList); + } + + public void printFully(PrintStream out) throws IOException + { + linkSupers(); + + ArrayList textList = classpath.getClassTextList(name); + + out.println("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-"); + out.println(); + String xname = "__" + name.replaceAll("/", "_") + "__"; + out.println("#ifndef " + xname); + out.println("#define " + xname); + out.println(); + out.println("#pragma interface"); + out.println(); + + if (superClass != null) + { + out.print("#include <"); + out.print(superName); + out.println(".h>"); + } + + // Write the body of the stream here. This lets + // us emit the namespaces without a second pass. + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + CniPrintStream cxxOut = new CniPrintStream(bytes); + cxxOut.addClass(this); + printContents(cxxOut, textList); + cxxOut.printNamespaces(out); + bytes.writeTo(out); + + out.println(); + out.println("#endif // " + xname); + } +} diff --git a/tools/gnu/classpath/tools/javah/CniIncludePrinter.java b/tools/gnu/classpath/tools/javah/CniIncludePrinter.java new file mode 100644 index 000000000..6561169bb --- /dev/null +++ b/tools/gnu/classpath/tools/javah/CniIncludePrinter.java @@ -0,0 +1,69 @@ +/* CniIncludePrinter.java - generate CNI header files + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +public class CniIncludePrinter + extends Printer +{ + + protected CniIncludePrinter(Main classpath) + { + super(classpath); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + // Never write Object or Class. This is a hack, maybe + // the user would like to see what they look like... + if (klass.name.equals("java/lang/Object") + || klass.name.equals("java/lang/Class")) + return; + File klassFile = new File(outputDir, klass.name + ".h"); + klassFile.getParentFile().mkdirs(); + PrintStream ps = new PrintStream(new FileOutputStream(klassFile)); + klass.printFully(ps); + ps.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/CniPrintStream.java b/tools/gnu/classpath/tools/javah/CniPrintStream.java new file mode 100644 index 000000000..574d7fd5f --- /dev/null +++ b/tools/gnu/classpath/tools/javah/CniPrintStream.java @@ -0,0 +1,243 @@ +/* CniPrintStream.java - PrintStream that emits CNI declarations + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashSet; + +import org.objectweb.asm.Type; + +public class CniPrintStream + extends PrintStream +{ + int currentModifiers = Modifier.PRIVATE; + + // True if we saw an array type. + boolean sawArray; + + // All the classes referenced by this header. + HashSet allClasses = new HashSet(); + + String[] previousPackage = new String[0]; + + public CniPrintStream(OutputStream out) + { + super(out); + } + + public void addClass(ClassWrapper cw) + { + allClasses.add(cw.name); + } + + public void setModifiers(int newMods) + { + newMods &= (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE); + if (newMods != currentModifiers) + { + switch (newMods) + { + case Modifier.PUBLIC: + println("public:"); + break; + case Modifier.PROTECTED: + println("public: // actually protected"); + break; + case Modifier.PRIVATE: + println("private:"); + break; + default: + println("public: // actually package-private"); + break; + } + currentModifiers = newMods; + } + } + + private String getName(Type type) + { + if (type == Type.BOOLEAN_TYPE) + return "jboolean"; + else if (type == Type.BYTE_TYPE) + return "jbyte"; + else if (type == Type.CHAR_TYPE) + return "jchar"; + else if (type == Type.SHORT_TYPE) + return "jshort"; + else if (type == Type.INT_TYPE) + return "jint"; + else if (type == Type.LONG_TYPE) + return "jlong"; + else if (type == Type.FLOAT_TYPE) + return "jfloat"; + else if (type == Type.DOUBLE_TYPE) + return "jdouble"; + else + { + assert type == Type.VOID_TYPE; + return "void"; + } + } + + public String getClassName(Type type) + { + String name = type.toString(); + name = name.substring(1, name.length() - 1); + // Add the plain class name; we'll handle it when + // we process namespaces. + allClasses.add(name); + return "::" + name.replaceAll("/", "::") + " *"; + } + + public void print(Type type) + { + int arrayCount = 0; + if (type.getSort() == Type.ARRAY) + { + arrayCount = type.getDimensions(); + for (int i = 0; i < arrayCount; ++i) + print("JArray< "); + type = type.getElementType(); + sawArray = true; + } + if (type.getSort() == Type.OBJECT) + { + print(getClassName(type)); + } + else + { + print(getName(type)); + } + if (arrayCount > 0) + { + while (arrayCount-- > 0) + { + print(" > *"); + } + } + } + + private void indent(PrintStream out, int n) + { + for (int i = 0; i < n; ++i) + { + out.print(" "); + } + } + + private void moveToPackage(PrintStream out, String[] pkgParts) + { + // Find greatest common part. + int commonIndex; + for (commonIndex = 0; commonIndex < previousPackage.length; ++commonIndex) + { + if (commonIndex >= pkgParts.length) + break; + if (! previousPackage[commonIndex].equals(pkgParts[commonIndex])) + break; + } + // Close old parts after the common part. + for (int j = previousPackage.length - 1; j >= commonIndex; --j) + { + indent(out, j + 1); + out.println("}"); + } + // Open new parts. + for (int j = commonIndex; j < pkgParts.length; ++j) + { + indent(out, j + 1); + out.print("namespace "); + out.println(pkgParts[j]); + indent(out, j + 1); + out.println("{"); + } + previousPackage = pkgParts; + } + + private void writeClass(PrintStream out, String klass) + { + int index = klass.lastIndexOf('/'); + String pkg = klass.substring(0, index); + String[] pkgParts = pkg.split("/"); + String className = klass.substring(index + 1); + moveToPackage(out, pkgParts); + indent(out, pkgParts.length + 2); + out.print("class "); + out.print(className); + out.println(";"); + } + + public void printNamespaces(PrintStream out) + { + if (sawArray) + { + out.println("#include <gcj/array.h>"); + out.println(); + } + + String[] classes = (String[]) allClasses.toArray(new String[0]); + Arrays.sort(classes); + + boolean first = true; + boolean seen = false; + for (int i = 0; i < classes.length; ++i) + { + String klass = classes[i]; + if (klass.startsWith("java/lang/") || klass.startsWith("java/io/") + || klass.startsWith("java/util/")) + continue; + if (first) + { + out.println("extern \"Java\""); + out.println("{"); + first = false; + seen = true; + } + writeClass(out, klass); + } + if (seen) + { + moveToPackage(out, new String[0]); + out.println("}"); + } + } +} diff --git a/tools/gnu/classpath/tools/javah/CniStubPrinter.java b/tools/gnu/classpath/tools/javah/CniStubPrinter.java new file mode 100644 index 000000000..9732e2941 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/CniStubPrinter.java @@ -0,0 +1,119 @@ +/* CniStubPrinter.java - Generate a CNI stub file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +public class CniStubPrinter + extends Printer +{ + + protected CniStubPrinter(Main classpath) + { + super(classpath); + } + + private void printDecl(CniPrintStream out, String className, MethodNode method) + { + out.print(className); + out.print("::"); + out.print(method.name); + out.print("("); + Type[] argTypes = Type.getArgumentTypes(method.desc); + for (int j = 0; j < argTypes.length; ++j) + { + if (j > 0) + out.print(", "); + out.print(argTypes[j]); + } + out.print(")"); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + if (! klass.hasNativeMethod()) + return; + File klassFile = new File(outputDir, klass.name + ".cc"); + klassFile.getParentFile().mkdirs(); + String className = klass.name.replaceAll("/", "::"); + + CniPrintStream out = new CniPrintStream(new FileOutputStream(klassFile)); + out.println("// This file is intended to give you a head start on implementing native"); + out.println("// methods using CNI."); + out.println("// Be aware: running 'gcjh -stubs' once more for this class may"); + out.println("// overwrite any edits you have made to this file."); + out.println(); + + out.println("#include <" + klass.name + ".h>"); + out.println("#include <gcj/cni.h>"); + out.println("#include <java/lang/UnsupportedOperationException.h>"); + out.println(); + + Iterator i = klass.methods.iterator(); + boolean first = true; + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + if (! first) + out.println(); + first = false; + out.print(Type.getReturnType(method.desc)); + out.println(); + printDecl(out, className, method); + out.println(); + out.println("{"); + out.print(" throw new ::java::lang::UnsupportedOperationException("); + out.print("JvNewStringLatin1 (\""); + printDecl(out, className, method); + out.println("\"));"); + out.println("}"); + } + out.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/FieldHelper.java b/tools/gnu/classpath/tools/javah/FieldHelper.java new file mode 100644 index 000000000..ecc82e3c1 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/FieldHelper.java @@ -0,0 +1,97 @@ +/* FieldHelper.java - field helper methods for CNI + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.lang.reflect.Modifier; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.FieldNode; + +public class FieldHelper +{ + public static boolean print(CniPrintStream out, FieldNode field, + ClassWrapper superType, boolean hasMethodName) + { + out.setModifiers(field.access); + out.print(" "); + if (Modifier.isStatic(field.access)) + out.print("static "); + if ((field.value instanceof Integer) || (field.value instanceof Long)) + out.print("const "); + out.print(Type.getType(field.desc)); + out.print(" "); + boolean result = false; + if (superType != null && ! Modifier.isStatic(field.access)) + { + out.print("__attribute__((aligned(__alignof__( "); + superType.print(out); + out.print(")))) "); + result = true; + } + out.print(Keywords.getCxxName(field.name)); + if (hasMethodName) + out.print("__"); + if (Modifier.isStatic(field.access)) + { + if (field.value instanceof Integer) + { + out.print(" = "); + int val = ((Integer) field.value).intValue(); + if (val == Integer.MIN_VALUE) + out.print("-" + Integer.MAX_VALUE + " - 1"); + else + out.print(val); + } + else if (field.value instanceof Long) + { + out.print(" = "); + long val = ((Long) field.value).longValue(); + if (val == Long.MIN_VALUE) + out.print("-" + Long.MAX_VALUE + "LL - 1"); + else + { + out.print(val); + out.print("LL"); + } + } + } + out.println(";"); + return result; + } +} diff --git a/tools/gnu/classpath/tools/javah/JniHelper.java b/tools/gnu/classpath/tools/javah/JniHelper.java new file mode 100644 index 000000000..3104cea5a --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniHelper.java @@ -0,0 +1,120 @@ +/* JniHelper.java - name mangling and other JNI support + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.IOException; + +import org.objectweb.asm.Type; + +public class JniHelper +{ + public static String getName(Main classpath, Type type) throws IOException + { + if (type == Type.BOOLEAN_TYPE) + return "jboolean"; + else if (type == Type.BYTE_TYPE) + return "jbyte"; + else if (type == Type.CHAR_TYPE) + return "jchar"; + else if (type == Type.SHORT_TYPE) + return "jshort"; + else if (type == Type.INT_TYPE) + return "jint"; + else if (type == Type.LONG_TYPE) + return "jlong"; + else if (type == Type.FLOAT_TYPE) + return "jfloat"; + else if (type == Type.DOUBLE_TYPE) + return "jdouble"; + else if (type == Type.VOID_TYPE) + return "void"; + + if (type.getSort() == Type.ARRAY) + { + Type elt = type.getElementType(); + int eltSort = elt.getSort(); + if (eltSort != Type.OBJECT && eltSort != Type.ARRAY) + return getName(classpath, elt) + "Array"; + return "jarray"; + } + + assert type.getSort() == Type.OBJECT; + String className = type.getClassName(); + // FIXME: is this correct? + if (className.equals("java/lang/Class") + || className.equals("java.lang.Class")) + return "jclass"; + if (className.equals("java/lang/String") + || className.equals("java.lang.String")) + return "jstring"; + + ClassWrapper klass = classpath.getClass(className); + if (klass.isThrowable()) + return "jthrowable"; + return "jobject"; + } + + public static String mangle(String name) + { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < name.length(); ++i) + { + char c = name.charAt(i); + if (c == '_') + result.append("_1"); + else if (c == ';') + result.append("_2"); + else if (c == '[') + result.append("_3"); + else if (c == '/') + result.append("_"); + else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) + result.append(c); + else + { + result.append("_0"); + // Sigh. + String hex = "0000" + Integer.toHexString(c); + result.append(hex.substring(hex.length() - 4)); + } + } + return result.toString(); + } +} diff --git a/tools/gnu/classpath/tools/javah/JniIncludePrinter.java b/tools/gnu/classpath/tools/javah/JniIncludePrinter.java new file mode 100644 index 000000000..36ab33bc1 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniIncludePrinter.java @@ -0,0 +1,144 @@ +/* JniIncludePrinter.java - Generate a JNI header file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public class JniIncludePrinter + extends Printer +{ + + protected JniIncludePrinter(Main classpath) + { + super(classpath); + } + + private void writeFields(ClassWrapper klass, JniPrintStream out) + { + boolean wroteAny = false; + for (; klass != null; klass = klass.superClass) + { + Iterator i = klass.fields.iterator(); + while (i.hasNext()) + { + FieldNode field = (FieldNode) i.next(); + if (! Modifier.isStatic(field.access) + || ! Modifier.isFinal(field.access) || field.value == null) + continue; + String name = (JniHelper.mangle(klass.name) + "_" + JniHelper.mangle(field.name)); + out.print("#undef "); + out.println(name); + out.print("#define "); + out.print(name); + out.print(" "); + out.print(field.value); + if (field.value instanceof Long) + out.print("LL"); + out.println(); + wroteAny = true; + } + } + if (wroteAny) + out.println(); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + if (! klass.hasNativeMethod()) + return; + String xname = JniHelper.mangle(klass.name); + File outFile = new File(outputDir, xname + ".h"); + + JniPrintStream out = new JniPrintStream(classpath, + new FileOutputStream(outFile), + klass); + out.println("/* DO NOT EDIT THIS FILE - it is machine generated */"); + out.println(); + out.print("#ifndef __"); + out.print(xname); + out.println("__"); + out.print("#define __"); + out.print(xname); + out.println("__"); + out.println(); + out.println("#include <jni.h>"); + out.println(); + out.println("#ifdef __cplusplus"); + out.println("extern \"C\""); + out.println("{"); + out.println("#endif"); + out.println(); + + Iterator i = klass.methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + out.print("JNIEXPORT "); + out.print(Type.getReturnType(method.desc)); + out.print(" JNICALL "); + out.print(method, xname); + out.println(";"); + } + + out.println(); + + writeFields(klass, out); + + out.println("#ifdef __cplusplus"); + out.println("}"); + out.println("#endif"); + out.println(); + out.print("#endif /* __"); + out.print(xname); + out.println("__ */"); + + out.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/JniPrintStream.java b/tools/gnu/classpath/tools/javah/JniPrintStream.java new file mode 100644 index 000000000..a0461f475 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniPrintStream.java @@ -0,0 +1,115 @@ +/* JniPrintStream.java - PrintStream that emits JNI declarations + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +public class JniPrintStream + extends PrintStream +{ + Main classpath; + + // This is used to determine whether a method has an overload. + HashMap methodNameMap = new HashMap(); + + public JniPrintStream(Main classpath, OutputStream out, ClassWrapper klass) + { + super(out); + this.classpath = classpath; + computeOverloads(klass); + } + + private void computeOverloads(ClassWrapper klass) + { + Iterator i = klass.methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + if (methodNameMap.containsKey(method.name)) + { + Integer val = (Integer) methodNameMap.get(method.name); + methodNameMap.put(method.name, new Integer(val.intValue() + 1)); + } + else + methodNameMap.put(method.name, new Integer(1)); + } + } + + public void print(Type type) throws IOException + { + print(JniHelper.getName(classpath, type)); + } + + public void print(MethodNode method, String className) throws IOException + { + print("Java_"); + print(className); + print("_"); + print(JniHelper.mangle(method.name)); + Integer overloadCount = (Integer) methodNameMap.get(method.name); + if (overloadCount.intValue() > 1) + { + print("__"); + int lastOffset = method.desc.lastIndexOf(')'); + print(JniHelper.mangle(method.desc.substring(1, lastOffset))); + } + print(" (JNIEnv *env"); + if (Modifier.isStatic(method.access)) + print(", jclass"); + else + print(", jobject"); + Type[] types = Type.getArgumentTypes(method.desc); + for (int i = 0; i < types.length; ++i) + { + print(", "); + print(types[i]); + } + print(")"); + } +} diff --git a/tools/gnu/classpath/tools/javah/JniStubPrinter.java b/tools/gnu/classpath/tools/javah/JniStubPrinter.java new file mode 100644 index 000000000..d590a5cd1 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniStubPrinter.java @@ -0,0 +1,98 @@ +/* JniStubPrinter.java - Generate JNI stub files + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +public class JniStubPrinter + extends Printer +{ + + protected JniStubPrinter(Main classpath) + { + super(classpath); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + if (! klass.hasNativeMethod()) + return; + String xname = JniHelper.mangle(klass.name); + File outFile = new File(outputDir, xname + ".c"); + + JniPrintStream out = new JniPrintStream(classpath, + new FileOutputStream(outFile), + klass); + out.println("/* This file is intended to give you a head start on implementing native"); + out.println(" methods using CNI."); + out.println(" Be aware: running 'gcjh -stubs' once more for this class may"); + out.println(" overwrite any edits you have made to this file. */"); + out.println(); + out.print("#include <"); + out.print(xname); + out.println(".h>"); + + Iterator i = klass.methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + out.println(); + out.print(Type.getReturnType(method.desc)); + out.println(); + out.print(method, xname); + out.println(); + out.println("{"); + out.print(" (*env)->FatalError (env, \""); + out.print(method, xname); + out.println(" not implemented\");"); + out.println("}"); + } + out.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/Keywords.java b/tools/gnu/classpath/tools/javah/Keywords.java new file mode 100644 index 000000000..46543ba45 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Keywords.java @@ -0,0 +1,85 @@ +/* Keywords.java - List of C++ keywords + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.util.HashSet; + +public class Keywords +{ + private static final String[] words = { "and", "and_eq", "asm", "auto", + "bitand", "bitor", "bool", "break", + "case", "catch", "char", "class", + "compl", "const", "const_cast", + "continue", "default", "delete", "do", + "double", "dynamic_cast", "else", + "enum", "explicit", "export", + "extern", "false", "float", "for", + "friend", "goto", "if", "inline", + "int", "long", "mutable", "namespace", + "new", "not", "not_eq", "operator", + "or", "or_eq", "private", "protected", + "public", "register", + "reinterpret_cast", "return", "short", + "signed", "sizeof", "static", + "static_cast", "struct", "switch", + "template", "this", "throw", "true", + "try", "typedef", "typeid", + "typename", "typeof", "union", + "unsigned", "using", "virtual", + "void", "volatile", "wchar_t", + "while", "xor", "xor_eq" }; + + private static final HashSet keywords; + static + { + keywords = new HashSet(); + for (int i = 0; i < words.length; ++i) + keywords.add(words[i]); + } + + public static String getCxxName(String name) + { + int i; + for (i = name.length() - 1; i >= 0 && name.charAt(i) == '$'; --i) + ; + if (keywords.contains(name.substring(0, i + 1))) + return name + "$"; + return name; + } +} diff --git a/tools/gnu/classpath/tools/javah/Main.java b/tools/gnu/classpath/tools/javah/Main.java new file mode 100644 index 000000000..f9b2f624c --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Main.java @@ -0,0 +1,375 @@ +/* Main.java - javah main program + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.Parser; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +import org.objectweb.asm.ClassReader; + +public class Main +{ + // This is an option group for classpath-related options, + // and also is used for loading classes. + PathOptionGroup classpath = new PathOptionGroup(); + + // The output directory. + String outputDir; + + // The loader that we use to load class files. + URLClassLoader loader; + + // In -all mode, the name of the directory to scan. + String allDirectory; + + // True for verbose mode. + boolean verbose; + + // True if we're emitting stubs. + boolean stubs; + + // True if we're emitting CNI code. + boolean cni; + + // Map class names to class wrappers. + HashMap classMap = new HashMap(); + + // Map class names to lists of Text objects. + HashMap textMap = new HashMap(); + + void readCommandFile(String textFileName) throws OptionException + { + FileInputStream fis; + try + { + fis = new FileInputStream(textFileName); + } + catch (FileNotFoundException ignore) + { + throw new OptionException("file \"" + textFileName + "\" not found"); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(fis)); + String currentClass = null; + ArrayList currentValues = null; + while (true) + { + String line; + try + { + line = reader.readLine(); + } + catch (IOException _) + { + break; + } + if (line == null) + break; + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') + continue; + int index = line.indexOf(' '); + String cmd = line.substring(0, index); + String value = line.substring(index + 1); + int cmdValue; + if ("class".equals(cmd)) + { + if (currentClass != null) + { + textMap.put(currentClass, currentValues); + } + currentClass = value; + currentValues = new ArrayList(); + continue; + } + if (currentClass == null) + throw new OptionException("no class set"); + if ("add".equals(cmd)) + cmdValue = Text.ADD; + else if ("append".equals(cmd)) + cmdValue = Text.APPEND; + else if ("prepend".equals(cmd)) + cmdValue = Text.PREPEND; + else if ("friend".equals(cmd)) + cmdValue = Text.FRIEND; + else + throw new OptionException("unrecognized command: " + cmd); + currentValues.add(new Text(cmdValue, value)); + } + if (currentClass != null) + { + textMap.put(currentClass, currentValues); + } + } + + void scanDirectory(File dir, final HashSet results) + { + File[] files = dir.listFiles(new FileFilter() + { + public boolean accept(File pathname) + { + if (pathname.isDirectory()) + { + scanDirectory(pathname, results); + return false; + } + return pathname.getName().endsWith(".class"); + } + }); + if (files != null) + results.addAll(Arrays.asList(files)); + } + + private Parser getParser() + { + ClasspathToolParser result = new ClasspathToolParser("gcjh", true); + result.setHeader("usage: gcjh [OPTIONS] CLASS..."); + result.add(classpath); + result.add(new Option('d', "Set output directory", "DIR") + { + public void parsed(String dir) throws OptionException + { + if (outputDir != null) + throw new OptionException("-d already seen"); + outputDir = dir; + } + }); + result.add(new Option("cmdfile", "Read command file", "FILE") + { + public void parsed(String file) throws OptionException + { + readCommandFile(file); + } + }); + result.add(new Option("all", "Operate on all class files under directory", + "DIR") + { + public void parsed(String arg) throws OptionException + { + // FIXME: lame restriction... + if (allDirectory != null) + throw new OptionException("-all already specified"); + allDirectory = arg; + } + }); + result.add(new Option("stubs", "Emit stub implementation") + { + public void parsed(String arg0) throws OptionException + { + stubs = true; + } + }); + result.add(new Option("cni", "Emit CNI stubs or header (default JNI)") + { + public void parsed(String arg0) throws OptionException + { + cni = true; + } + }); + result.add(new Option("verbose", "Set verbose mode") + { + public void parsed(String arg0) throws OptionException + { + verbose = true; + } + }); + return result; + } + + private File makeOutputDirectory() throws IOException + { + File outputFile; + if (outputDir == null) + outputFile = new File("."); + else + { + outputFile = new File(outputDir); + outputFile.mkdirs(); + } + return outputFile; + } + + private void writeHeaders(ArrayList klasses, Printer printer, + File outputDirFile) throws IOException + { + Iterator i = klasses.iterator(); + while (i.hasNext()) + { + ClassWrapper klass = (ClassWrapper) i.next(); + if (verbose) + System.err.println("[writing " + klass + "]"); + printer.printClass(outputDirFile, klass); + } + } + + private void run(String[] args) throws IOException + { + Parser p = getParser(); + String[] classNames = p.parse(args); + loader = classpath.getLoader(); + + File outputFile = makeOutputDirectory(); + Printer printer; + if (! cni) + { + if (stubs) + printer = new JniStubPrinter(this); + else + printer = new JniIncludePrinter(this); + } + else + { + if (stubs) + printer = new CniStubPrinter(this); + else + printer = new CniIncludePrinter(this); + } + + // First we load all of the files. That way if + // there are references between the files we will + // be loading the set that the user asked for. + HashSet klasses = new HashSet(); + if (allDirectory != null) + scanDirectory(new File(allDirectory), klasses); + // Add the command-line arguments. We use the type of + // an item in 'klasses' to decide how to load each class. + for (int i = 0; i < classNames.length; ++i) + { + if (classNames[i].endsWith(".class")) + { + klasses.add(new File(classNames[i])); + } + else + { + klasses.add(classNames[i]); + } + } + + Iterator i = klasses.iterator(); + ArrayList results = new ArrayList(); + while (i.hasNext()) + { + // Let user specify either kind of class name or a + // file name. + Object item = i.next(); + ClassWrapper klass; + if (item instanceof File) + { + // Load class from file. + if (verbose) + System.err.println("[reading file " + item + "]"); + klass = getClass((File) item); + } + else + { + // Load class given the class name. + String className = ((String) item).replace('.', '/'); + if (verbose) + System.err.println("[reading class " + className + "]"); + klass = getClass(className); + } + results.add(klass); + } + + writeHeaders(results, printer, outputFile); + } + + public ArrayList getClassTextList(String name) + { + return (ArrayList) textMap.get(name); + } + + private ClassWrapper readClass(InputStream is) throws IOException + { + ClassReader r = new ClassReader(is); + ClassWrapper result = new ClassWrapper(this); + r.accept(result, true); + is.close(); + return result; + } + + private ClassWrapper getClass(File fileName) throws IOException + { + InputStream is = new FileInputStream(fileName); + ClassWrapper result = readClass(is); + if (classMap.containsKey(result.name)) + throw new IllegalArgumentException("class " + result.name + + " already loaded"); + classMap.put(result.name, result); + return result; + } + + public ClassWrapper getClass(String name) throws IOException + { + if (! classMap.containsKey(name)) + { + String resource = name.replace('.', '/') + ".class"; + URL url = loader.findResource(resource); + if (url == null) + throw new IOException("can't find class file " + resource); + InputStream is = url.openStream(); + ClassWrapper result = readClass(is); + classMap.put(name, result); + } + return (ClassWrapper) classMap.get(name); + } + + public static void main(String[] args) throws IOException + { + Main m = new Main(); + m.run(args); + } +} diff --git a/tools/gnu/classpath/tools/javah/MethodHelper.java b/tools/gnu/classpath/tools/javah/MethodHelper.java new file mode 100644 index 000000000..6657f115a --- /dev/null +++ b/tools/gnu/classpath/tools/javah/MethodHelper.java @@ -0,0 +1,130 @@ +/* MethodHelper.java - helper class for manipulating methods + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class MethodHelper +{ + + public static boolean overrides(MethodNode derived, MethodNode base) + { + if (! derived.name.equals(base.name)) + return false; + if (! derived.desc.equals(base.desc)) + return false; + // FIXME: permission madness? + return true; + } + + public static String getBridgeTarget(MethodNode meth) + { + if ((meth.access & Opcodes.ACC_BRIDGE) == 0) + return null; + Iterator i = meth.instructions.iterator(); + while (i.hasNext()) + { + AbstractInsnNode insn = (AbstractInsnNode) i.next(); + if (! (insn instanceof MethodInsnNode)) + continue; + return ((MethodInsnNode) insn).desc; + } + return null; + } + + public static void print(CniPrintStream out, MethodNode meth, + ClassWrapper declarer, boolean isBridgeTarget) + { + if ("<clinit>".equals(meth.name)) + return; + boolean isInit = "<init>".equals(meth.name); + out.setModifiers(meth.access); + out.print(" "); + if (Modifier.isStatic(meth.access)) + out.print("static "); + // If a class is final then we might as well skip 'virtual'. + // The reason here is that it is safe in this case for C++ + // ABI code to generate a direct call. The method does end + // up in the vtable (for BC code) but we don't care. Also, + // the class can't be derived from anyway. + else if (! isInit && ! Modifier.isPrivate(meth.access) + && ! Modifier.isFinal(declarer.access)) + out.print("virtual "); + if (! isInit) + { + out.print(Type.getReturnType(meth.desc)); + out.print(" "); + if (isBridgeTarget) + { + out.print("target$"); + out.print(meth.name); + } + else + { + out.print(Keywords.getCxxName(meth.name)); + } + } + else + { + String name = declarer.name; + int index = name.lastIndexOf('/'); + name = name.substring(index + 1); + out.print(name); + } + out.print("("); + Type[] argTypes = Type.getArgumentTypes(meth.desc); + for (int i = 0; i < argTypes.length; ++i) + { + if (i > 0) + out.print(", "); + out.print(argTypes[i]); + } + out.print(")"); + if (Modifier.isAbstract(meth.access)) + out.print(" = 0"); + out.println(";"); + } +} diff --git a/tools/gnu/classpath/tools/javah/PackageWrapper.java b/tools/gnu/classpath/tools/javah/PackageWrapper.java new file mode 100644 index 000000000..11b38b20f --- /dev/null +++ b/tools/gnu/classpath/tools/javah/PackageWrapper.java @@ -0,0 +1,54 @@ +/* PackageWrapper.java - represent a package + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +public class PackageWrapper +{ + // This is null if there is no parent package. + PackageWrapper parent; + + // Name of this package relative to its parent's name. + String name; + + public PackageWrapper(PackageWrapper parent, String name) + { + this.parent = parent; + this.name = name; + } +} diff --git a/tools/gnu/classpath/tools/javah/PathOptionGroup.java b/tools/gnu/classpath/tools/javah/PathOptionGroup.java new file mode 100644 index 000000000..f11077fa0 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/PathOptionGroup.java @@ -0,0 +1,135 @@ +/* PathOptionGroup.java - handle classpath-setting options + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.StringTokenizer; + +public class PathOptionGroup + extends OptionGroup +{ + ArrayList classpath = new ArrayList(); + + ArrayList bootclasspath = new ArrayList(); + + void setPath(ArrayList list, String path) + { + list.clear(); + StringTokenizer st = new StringTokenizer(path, File.pathSeparator); + while (st.hasMoreTokens()) + { + list.add(st.nextToken()); + } + } + + void addExtDirs(ArrayList list, String path) + { + StringTokenizer tok = new StringTokenizer(path, File.pathSeparator); + while (tok.hasMoreTokens()) + { + File dir = new File(tok.nextToken()); + list.addAll(Arrays.asList(dir.list(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.endsWith(".zip") || name.endsWith(".jar"); + } + }))); + } + } + + public PathOptionGroup() + { + super("Class path options"); + + add(new Option("classpath", "Set the class path", "PATH") + { + public void parsed(String path) throws OptionException + { + setPath(classpath, path); + } + }); + add(new Option('I', "Add directory to class path", "DIR") + { + public void parsed(String path) throws OptionException + { + classpath.add(path); + } + }); + add(new Option("bootclasspath", "Set the boot class path", "PATH") + { + public void parsed(String path) throws OptionException + { + setPath(bootclasspath, path); + } + }); + add(new Option("extdirs", "Set the extension directory path", "PATH") + { + public void parsed(String path) throws OptionException + { + addExtDirs(classpath, path); + } + }); + } + + public URLClassLoader getLoader() throws MalformedURLException + { + ArrayList urls = new ArrayList(); + classpath.addAll(bootclasspath); + Iterator i = classpath.iterator(); + while (i.hasNext()) + { + String f = (String) i.next(); + urls.add(new File(f).toURL()); + } + URL[] urlArray = (URL[]) urls.toArray(new URL[0]); + return new URLClassLoader(urlArray); + } +} diff --git a/tools/gnu/classpath/tools/javah/Printer.java b/tools/gnu/classpath/tools/javah/Printer.java new file mode 100644 index 000000000..0c25934e2 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Printer.java @@ -0,0 +1,55 @@ +/* Print.java - abstract base class for printing classes + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.IOException; + +public abstract class Printer +{ + protected Main classpath; + + protected Printer(Main classpath) + { + this.classpath = classpath; + } + + public abstract void printClass(File outputDir, ClassWrapper klass) + throws IOException; +} diff --git a/tools/gnu/classpath/tools/javah/Text.java b/tools/gnu/classpath/tools/javah/Text.java new file mode 100644 index 000000000..37a1ad669 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Text.java @@ -0,0 +1,60 @@ +/* Text.java - convenience class for CNI header text insertions + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +public class Text +{ + public static final int ADD = 0; + + public static final int APPEND = 1; + + public static final int FRIEND = 2; + + public static final int PREPEND = 3; + + public int type; + + public String text; + + public Text(int type, String text) + { + this.type = type; + this.text = text; + } +} |