src/share/classes/com/sun/tools/javah/Gen.java

Wed, 02 Jun 2010 19:08:47 -0700

author
darcy
date
Wed, 02 Jun 2010 19:08:47 -0700
changeset 575
9a7c998bf2fc
parent 554
9d9f26857129
child 581
f2fdd52e4e87
permissions
-rw-r--r--

6933147: Provided new utility visitors supporting SourceVersion.RELEASE_7
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javah;
    28 import java.io.UnsupportedEncodingException;
    29 import java.io.ByteArrayOutputStream;
    30 import java.io.FileNotFoundException;
    31 import java.io.IOException;
    32 import java.io.InputStream;
    33 import java.io.OutputStream;
    34 import java.io.OutputStreamWriter;
    35 import java.io.PrintWriter;
    36 import java.util.ArrayList;
    37 import java.util.Arrays;
    38 import java.util.List;
    39 import java.util.Set;
    40 import java.util.Stack;
    42 import javax.annotation.processing.ProcessingEnvironment;
    44 import javax.lang.model.element.ExecutableElement;
    45 import javax.lang.model.element.Modifier;
    46 import javax.lang.model.element.TypeElement;
    47 import javax.lang.model.element.VariableElement;
    48 import javax.lang.model.util.ElementFilter;
    49 import javax.lang.model.util.Elements;
    50 import javax.lang.model.util.Types;
    52 import javax.tools.FileObject;
    53 import javax.tools.JavaFileManager;
    54 import javax.tools.JavaFileObject;
    55 import javax.tools.StandardLocation;
    57 /**
    58  * An abstraction for generating support files required by native methods.
    59  * Subclasses are for specific native interfaces. At the time of its
    60  * original writing, this interface is rich enough to support JNI and the
    61  * old 1.0-style native method interface.
    62  *
    63  * <p><b>This is NOT part of any API supported by Sun Microsystems.
    64  * If you write code that depends on this, you do so at your own
    65  * risk.  This code and its internal interfaces are subject to change
    66  * or deletion without notice.</b></p>
    67  *
    68  * @author  Sucheta Dambalkar(Revised)
    69  */
    70 public abstract class Gen {
    71     protected String lineSep = System.getProperty("line.separator");
    73     protected ProcessingEnvironment processingEnvironment;
    74     protected Types types;
    75     protected Elements elems;
    76     protected Mangle mangler;
    77     protected Util util;
    79     protected Gen(Util util) {
    80         this.util = util;
    81     }
    83     /*
    84      * List of classes for which we must generate output.
    85      */
    86     protected Set<TypeElement> classes;
    87     static private final boolean isWindows =
    88         System.getProperty("os.name").startsWith("Windows");
    91     /**
    92      * Override this abstract method, generating content for the named
    93      * class into the outputstream.
    94      */
    95     protected abstract void write(OutputStream o, TypeElement clazz) throws Util.Exit;
    97     /**
    98      * Override this method to provide a list of #include statements
    99      * required by the native interface.
   100      */
   101     protected abstract String getIncludes();
   103     /*
   104      * Output location.
   105      */
   106     protected JavaFileManager fileManager;
   107     protected JavaFileObject outFile;
   109     public void setFileManager(JavaFileManager fm) {
   110         fileManager = fm;
   111     }
   113     public void setOutFile(JavaFileObject outFile) {
   114         this.outFile = outFile;
   115     }
   118     public void setClasses(Set<TypeElement> classes) {
   119         this.classes = classes;
   120     }
   122     void setProcessingEnvironment(ProcessingEnvironment pEnv) {
   123         processingEnvironment = pEnv;
   124         elems = pEnv.getElementUtils();
   125         types = pEnv.getTypeUtils();
   126         mangler = new Mangle(elems, types);
   127     }
   129     /*
   130      * Smartness with generated files.
   131      */
   132     protected boolean force = false;
   134     public void setForce(boolean state) {
   135         force = state;
   136     }
   138     /**
   139      * We explicitly need to write ASCII files because that is what C
   140      * compilers understand.
   141      */
   142     protected PrintWriter wrapWriter(OutputStream o) throws Util.Exit {
   143         try {
   144             return new PrintWriter(new OutputStreamWriter(o, "ISO8859_1"), true);
   145         } catch (UnsupportedEncodingException use) {
   146             util.bug("encoding.iso8859_1.not.found");
   147             return null; /* dead code */
   148         }
   149     }
   151     /**
   152      * After initializing state of an instance, use this method to start
   153      * processing.
   154      *
   155      * Buffer size chosen as an approximation from a single sampling of:
   156      *         expr `du -sk` / `ls *.h | wc -l`
   157      */
   158     public void run() throws IOException, ClassNotFoundException, Util.Exit {
   159         int i = 0;
   160         if (outFile != null) {
   161             /* Everything goes to one big file... */
   162             ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
   163             writeFileTop(bout); /* only once */
   165             for (TypeElement t: classes) {
   166                 write(bout, t);
   167             }
   169             writeIfChanged(bout.toByteArray(), outFile);
   170         } else {
   171             /* Each class goes to its own file... */
   172             for (TypeElement t: classes) {
   173                 ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
   174                 writeFileTop(bout);
   175                 write(bout, t);
   176                 writeIfChanged(bout.toByteArray(), getFileObject(t.getQualifiedName()));
   177             }
   178         }
   179     }
   181     /*
   182      * Write the contents of byte[] b to a file named file.  Writing
   183      * is done if either the file doesn't exist or if the contents are
   184      * different.
   185      */
   186     private void writeIfChanged(byte[] b, FileObject file) throws IOException {
   187         boolean mustWrite = false;
   188         String event = "[No need to update file ";
   190         if (force) {
   191             mustWrite = true;
   192             event = "[Forcefully writing file ";
   193         } else {
   194             InputStream in;
   195             byte[] a;
   196             try {
   197                 // regrettably, there's no API to get the length in bytes
   198                 // for a FileObject, so we can't short-circuit reading the
   199                 // file here
   200                 in = file.openInputStream();
   201                 a = readBytes(in);
   202                 if (!Arrays.equals(a, b)) {
   203                     mustWrite = true;
   204                     event = "[Overwriting file ";
   206                 }
   207             } catch (FileNotFoundException e) {
   208                 mustWrite = true;
   209                 event = "[Creating file ";
   210             }
   211         }
   213         if (util.verbose)
   214             util.log(event + file + "]");
   216         if (mustWrite) {
   217             OutputStream out = file.openOutputStream();
   218             out.write(b); /* No buffering, just one big write! */
   219             out.close();
   220         }
   221     }
   223     protected byte[] readBytes(InputStream in) throws IOException {
   224         try {
   225             byte[] array = new byte[in.available() + 1];
   226             int offset = 0;
   227             int n;
   228             while ((n = in.read(array, offset, array.length - offset)) != -1) {
   229                 offset += n;
   230                 if (offset == array.length)
   231                     array = Arrays.copyOf(array, array.length * 2);
   232             }
   234             return Arrays.copyOf(array, offset);
   235         } finally {
   236             in.close();
   237         }
   238     }
   240     protected String defineForStatic(TypeElement c, VariableElement f)
   241             throws Util.Exit {
   242         CharSequence cnamedoc = c.getQualifiedName();
   243         CharSequence fnamedoc = f.getSimpleName();
   245         String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS);
   246         String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
   248         if (!f.getModifiers().contains(Modifier.STATIC))
   249             util.bug("tried.to.define.non.static");
   251         if (f.getModifiers().contains(Modifier.FINAL)) {
   252             Object value = null;
   254             value = f.getConstantValue();
   256             if (value != null) { /* so it is a ConstantExpression */
   257                 String constString = null;
   258                 if ((value instanceof Integer)
   259                     || (value instanceof Byte)
   260                     || (value instanceof Short)) {
   261                     /* covers byte, short, int */
   262                     constString = value.toString() + "L";
   263                 } else if (value instanceof Boolean) {
   264                     constString = ((Boolean) value) ? "1L" : "0L";
   265                 } else if (value instanceof Character) {
   266                     Character ch = (Character) value;
   267                     constString = String.valueOf(((int) ch) & 0xffff) + "L";
   268                 } else if (value instanceof Long) {
   269                     // Visual C++ supports the i64 suffix, not LL.
   270                     if (isWindows)
   271                         constString = value.toString() + "i64";
   272                     else
   273                         constString = value.toString() + "LL";
   274                 } else if (value instanceof Float) {
   275                     /* bug for bug */
   276                     float fv = ((Float)value).floatValue();
   277                     if (Float.isInfinite(fv))
   278                         constString = ((fv < 0) ? "-" : "") + "Inff";
   279                     else
   280                         constString = value.toString() + "f";
   281                 } else if (value instanceof Double) {
   282                     /* bug for bug */
   283                     double d = ((Double)value).doubleValue();
   284                     if (Double.isInfinite(d))
   285                         constString = ((d < 0) ? "-" : "") + "InfD";
   286                     else
   287                         constString = value.toString();
   288                 }
   289                 if (constString != null) {
   290                     StringBuffer s = new StringBuffer("#undef ");
   291                     s.append(cname); s.append("_"); s.append(fname); s.append(lineSep);
   292                     s.append("#define "); s.append(cname); s.append("_");
   293                     s.append(fname); s.append(" "); s.append(constString);
   294                     return s.toString();
   295                 }
   297             }
   298         }
   299         return null;
   300     }
   302     /*
   303      * Deal with the C pre-processor.
   304      */
   305     protected String cppGuardBegin() {
   306         return "#ifdef __cplusplus" + lineSep + "extern \"C\" {" + lineSep + "#endif";
   307     }
   309     protected String cppGuardEnd() {
   310         return "#ifdef __cplusplus" + lineSep + "}" + lineSep + "#endif";
   311     }
   313     protected String guardBegin(String cname) {
   314         return "/* Header for class " + cname + " */" + lineSep + lineSep +
   315             "#ifndef _Included_" + cname + lineSep +
   316             "#define _Included_" + cname;
   317     }
   319     protected String guardEnd(String cname) {
   320         return "#endif";
   321     }
   323     /*
   324      * File name and file preamble related operations.
   325      */
   326     protected void writeFileTop(OutputStream o) throws Util.Exit {
   327         PrintWriter pw = wrapWriter(o);
   328         pw.println("/* DO NOT EDIT THIS FILE - it is machine generated */" + lineSep +
   329                    getIncludes());
   330     }
   332     protected String baseFileName(CharSequence className) {
   333         return mangler.mangle(className, Mangle.Type.CLASS);
   334     }
   336     protected FileObject getFileObject(CharSequence className) throws IOException {
   337         String name = baseFileName(className) + getFileSuffix();
   338         return fileManager.getFileForOutput(StandardLocation.SOURCE_OUTPUT, "", name, null);
   339     }
   341     protected String getFileSuffix() {
   342         return ".h";
   343     }
   345     /**
   346      * Including super classes' fields.
   347      */
   349     List<VariableElement> getAllFields(TypeElement subclazz) {
   350         List<VariableElement> fields = new ArrayList<VariableElement>();
   351         TypeElement cd = null;
   352         Stack<TypeElement> s = new Stack<TypeElement>();
   354         cd = subclazz;
   355         while (true) {
   356             s.push(cd);
   357             TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass()));
   358             if (c == null)
   359                 break;
   360             cd = c;
   361         }
   363         while (!s.empty()) {
   364             cd = s.pop();
   365             fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements()));
   366         }
   368         return fields;
   369     }
   371     // c.f. MethodDoc.signature
   372     String signature(ExecutableElement e) {
   373         StringBuffer sb = new StringBuffer("(");
   374         String sep = "";
   375         for (VariableElement p: e.getParameters()) {
   376             sb.append(sep);
   377             sb.append(types.erasure(p.asType()).toString());
   378             sep = ",";
   379         }
   380         sb.append(")");
   381         return sb.toString();
   382     }
   383 }

mercurial