src/jdk.compiler/share/classes/com/sun/tools/javah/Gen.java
changeset 48464 0c0b618a20b1
parent 48463 474cec233fb2
parent 48341 626d11295f31
child 48465 f82e79958beb
equal deleted inserted replaced
48463:474cec233fb2 48464:0c0b618a20b1
     1 /*
       
     2  * Copyright (c) 2002, 2014, 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  */
       
    25 
       
    26 package com.sun.tools.javah;
       
    27 
       
    28 import java.io.ByteArrayOutputStream;
       
    29 import java.io.FileNotFoundException;
       
    30 import java.io.IOException;
       
    31 import java.io.InputStream;
       
    32 import java.io.OutputStream;
       
    33 import java.io.OutputStreamWriter;
       
    34 import java.io.PrintWriter;
       
    35 import java.io.UnsupportedEncodingException;
       
    36 import java.nio.file.NoSuchFileException;
       
    37 import java.util.ArrayList;
       
    38 import java.util.Arrays;
       
    39 import java.util.List;
       
    40 import java.util.Set;
       
    41 import java.util.Stack;
       
    42 
       
    43 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;
       
    51 import javax.tools.FileObject;
       
    52 import javax.tools.JavaFileManager;
       
    53 import javax.tools.JavaFileObject;
       
    54 import javax.tools.StandardLocation;
       
    55 
       
    56 /**
       
    57  * An abstraction for generating support files required by native methods.
       
    58  * Subclasses are for specific native interfaces. At the time of its
       
    59  * original writing, this interface is rich enough to support JNI and the
       
    60  * old 1.0-style native method interface.
       
    61  *
       
    62  * <p><b>This is NOT part of any supported API.
       
    63  * If you write code that depends on this, you do so at your own
       
    64  * risk.  This code and its internal interfaces are subject to change
       
    65  * or deletion without notice.</b></p>
       
    66  *
       
    67  * @author  Sucheta Dambalkar(Revised)
       
    68  */
       
    69 public abstract class Gen {
       
    70     protected String lineSep = System.getProperty("line.separator");
       
    71 
       
    72     protected ProcessingEnvironment processingEnvironment;
       
    73     protected Types types;
       
    74     protected Elements elems;
       
    75     protected Mangle mangler;
       
    76     protected Util util;
       
    77 
       
    78     protected Gen(Util util) {
       
    79         this.util = util;
       
    80     }
       
    81 
       
    82     /*
       
    83      * List of classes for which we must generate output.
       
    84      */
       
    85     protected Set<TypeElement> classes;
       
    86     static private final boolean isWindows =
       
    87         System.getProperty("os.name").startsWith("Windows");
       
    88 
       
    89 
       
    90     /**
       
    91      * Override this abstract method, generating content for the named
       
    92      * class into the outputstream.
       
    93      */
       
    94     protected abstract void write(OutputStream o, TypeElement clazz) throws Util.Exit;
       
    95 
       
    96     /**
       
    97      * Override this method to provide a list of #include statements
       
    98      * required by the native interface.
       
    99      */
       
   100     protected abstract String getIncludes();
       
   101 
       
   102     /*
       
   103      * Output location.
       
   104      */
       
   105     protected JavaFileManager fileManager;
       
   106     protected JavaFileObject outFile;
       
   107 
       
   108     public void setFileManager(JavaFileManager fm) {
       
   109         fileManager = fm;
       
   110     }
       
   111 
       
   112     public void setOutFile(JavaFileObject outFile) {
       
   113         this.outFile = outFile;
       
   114     }
       
   115 
       
   116 
       
   117     public void setClasses(Set<TypeElement> classes) {
       
   118         this.classes = classes;
       
   119     }
       
   120 
       
   121     void setProcessingEnvironment(ProcessingEnvironment pEnv) {
       
   122         processingEnvironment = pEnv;
       
   123         elems = pEnv.getElementUtils();
       
   124         types = pEnv.getTypeUtils();
       
   125         mangler = new Mangle(elems, types);
       
   126     }
       
   127 
       
   128     /*
       
   129      * Smartness with generated files.
       
   130      */
       
   131     protected boolean force = false;
       
   132 
       
   133     public void setForce(boolean state) {
       
   134         force = state;
       
   135     }
       
   136 
       
   137     /**
       
   138      * We explicitly need to write ASCII files because that is what C
       
   139      * compilers understand.
       
   140      */
       
   141     protected PrintWriter wrapWriter(OutputStream o) throws Util.Exit {
       
   142         try {
       
   143             return new PrintWriter(new OutputStreamWriter(o, "ISO8859_1"), true);
       
   144         } catch (UnsupportedEncodingException use) {
       
   145             util.bug("encoding.iso8859_1.not.found");
       
   146             return null; /* dead code */
       
   147         }
       
   148     }
       
   149 
       
   150     /**
       
   151      * After initializing state of an instance, use this method to start
       
   152      * processing.
       
   153      *
       
   154      * Buffer size chosen as an approximation from a single sampling of:
       
   155      *         expr `du -sk` / `ls *.h | wc -l`
       
   156      */
       
   157     public void run() throws IOException, ClassNotFoundException, Util.Exit {
       
   158         int i = 0;
       
   159         if (outFile != null) {
       
   160             /* Everything goes to one big file... */
       
   161             ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
       
   162             writeFileTop(bout); /* only once */
       
   163 
       
   164             for (TypeElement t: classes) {
       
   165                 write(bout, t);
       
   166             }
       
   167 
       
   168             writeIfChanged(bout.toByteArray(), outFile);
       
   169         } else {
       
   170             /* Each class goes to its own file... */
       
   171             for (TypeElement t: classes) {
       
   172                 ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
       
   173                 writeFileTop(bout);
       
   174                 write(bout, t);
       
   175                 writeIfChanged(bout.toByteArray(), getFileObject(t.getQualifiedName()));
       
   176             }
       
   177         }
       
   178     }
       
   179 
       
   180     /*
       
   181      * Write the contents of byte[] b to a file named file.  Writing
       
   182      * is done if either the file doesn't exist or if the contents are
       
   183      * different.
       
   184      */
       
   185     private void writeIfChanged(byte[] b, FileObject file) throws IOException {
       
   186         boolean mustWrite = false;
       
   187         String event = "[No need to update file ";
       
   188 
       
   189         if (force) {
       
   190             mustWrite = true;
       
   191             event = "[Forcefully writing file ";
       
   192         } else {
       
   193             InputStream in;
       
   194             byte[] a;
       
   195             try {
       
   196                 // regrettably, there's no API to get the length in bytes
       
   197                 // for a FileObject, so we can't short-circuit reading the
       
   198                 // file here
       
   199                 in = file.openInputStream();
       
   200                 a = readBytes(in);
       
   201                 if (!Arrays.equals(a, b)) {
       
   202                     mustWrite = true;
       
   203                     event = "[Overwriting file ";
       
   204 
       
   205                 }
       
   206             } catch (FileNotFoundException | NoSuchFileException e) {
       
   207                 mustWrite = true;
       
   208                 event = "[Creating file ";
       
   209             }
       
   210         }
       
   211 
       
   212         if (util.verbose)
       
   213             util.log(event + file + "]");
       
   214 
       
   215         if (mustWrite) {
       
   216             OutputStream out = file.openOutputStream();
       
   217             out.write(b); /* No buffering, just one big write! */
       
   218             out.close();
       
   219         }
       
   220     }
       
   221 
       
   222     protected byte[] readBytes(InputStream in) throws IOException {
       
   223         try {
       
   224             byte[] array = new byte[in.available() + 1];
       
   225             int offset = 0;
       
   226             int n;
       
   227             while ((n = in.read(array, offset, array.length - offset)) != -1) {
       
   228                 offset += n;
       
   229                 if (offset == array.length)
       
   230                     array = Arrays.copyOf(array, array.length * 2);
       
   231             }
       
   232 
       
   233             return Arrays.copyOf(array, offset);
       
   234         } finally {
       
   235             in.close();
       
   236         }
       
   237     }
       
   238 
       
   239     protected String defineForStatic(TypeElement c, VariableElement f)
       
   240             throws Util.Exit {
       
   241         CharSequence cnamedoc = c.getQualifiedName();
       
   242         CharSequence fnamedoc = f.getSimpleName();
       
   243 
       
   244         String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS);
       
   245         String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
       
   246 
       
   247         if (!f.getModifiers().contains(Modifier.STATIC))
       
   248             util.bug("tried.to.define.non.static");
       
   249 
       
   250         if (f.getModifiers().contains(Modifier.FINAL)) {
       
   251             Object value = null;
       
   252 
       
   253             value = f.getConstantValue();
       
   254 
       
   255             if (value != null) { /* so it is a ConstantExpression */
       
   256                 String constString = null;
       
   257                 if ((value instanceof Integer)
       
   258                     || (value instanceof Byte)
       
   259                     || (value instanceof Short)) {
       
   260                     /* covers byte, short, int */
       
   261                     constString = value.toString() + "L";
       
   262                 } else if (value instanceof Boolean) {
       
   263                     constString = ((Boolean) value) ? "1L" : "0L";
       
   264                 } else if (value instanceof Character) {
       
   265                     Character ch = (Character) value;
       
   266                     constString = String.valueOf(((int) ch) & 0xffff) + "L";
       
   267                 } else if (value instanceof Long) {
       
   268                     // Visual C++ supports the i64 suffix, not LL.
       
   269                     if (isWindows)
       
   270                         constString = value.toString() + "i64";
       
   271                     else
       
   272                         constString = value.toString() + "LL";
       
   273                 } else if (value instanceof Float) {
       
   274                     /* bug for bug */
       
   275                     float fv = ((Float)value).floatValue();
       
   276                     if (Float.isInfinite(fv))
       
   277                         constString = ((fv < 0) ? "-" : "") + "Inff";
       
   278                     else
       
   279                         constString = value.toString() + "f";
       
   280                 } else if (value instanceof Double) {
       
   281                     /* bug for bug */
       
   282                     double d = ((Double)value).doubleValue();
       
   283                     if (Double.isInfinite(d))
       
   284                         constString = ((d < 0) ? "-" : "") + "InfD";
       
   285                     else
       
   286                         constString = value.toString();
       
   287                 }
       
   288                 if (constString != null) {
       
   289                     StringBuilder s = new StringBuilder("#undef ");
       
   290                     s.append(cname); s.append("_"); s.append(fname); s.append(lineSep);
       
   291                     s.append("#define "); s.append(cname); s.append("_");
       
   292                     s.append(fname); s.append(" "); s.append(constString);
       
   293                     return s.toString();
       
   294                 }
       
   295 
       
   296             }
       
   297         }
       
   298         return null;
       
   299     }
       
   300 
       
   301     /*
       
   302      * Deal with the C pre-processor.
       
   303      */
       
   304     protected String cppGuardBegin() {
       
   305         return "#ifdef __cplusplus" + lineSep + "extern \"C\" {" + lineSep + "#endif";
       
   306     }
       
   307 
       
   308     protected String cppGuardEnd() {
       
   309         return "#ifdef __cplusplus" + lineSep + "}" + lineSep + "#endif";
       
   310     }
       
   311 
       
   312     protected String guardBegin(String cname) {
       
   313         return "/* Header for class " + cname + " */" + lineSep + lineSep +
       
   314             "#ifndef _Included_" + cname + lineSep +
       
   315             "#define _Included_" + cname;
       
   316     }
       
   317 
       
   318     protected String guardEnd(String cname) {
       
   319         return "#endif";
       
   320     }
       
   321 
       
   322     /*
       
   323      * File name and file preamble related operations.
       
   324      */
       
   325     protected void writeFileTop(OutputStream o) throws Util.Exit {
       
   326         PrintWriter pw = wrapWriter(o);
       
   327         pw.println("/* DO NOT EDIT THIS FILE - it is machine generated */" + lineSep +
       
   328                    getIncludes());
       
   329     }
       
   330 
       
   331     protected String baseFileName(CharSequence className) {
       
   332         return mangler.mangle(className, Mangle.Type.CLASS);
       
   333     }
       
   334 
       
   335     protected FileObject getFileObject(CharSequence className) throws IOException {
       
   336         String name = baseFileName(className) + getFileSuffix();
       
   337         return fileManager.getFileForOutput(StandardLocation.SOURCE_OUTPUT, "", name, null);
       
   338     }
       
   339 
       
   340     protected String getFileSuffix() {
       
   341         return ".h";
       
   342     }
       
   343 
       
   344     /**
       
   345      * Including super classes' fields.
       
   346      */
       
   347 
       
   348     List<VariableElement> getAllFields(TypeElement subclazz) {
       
   349         List<VariableElement> fields = new ArrayList<>();
       
   350         TypeElement cd = null;
       
   351         Stack<TypeElement> s = new Stack<>();
       
   352 
       
   353         cd = subclazz;
       
   354         while (true) {
       
   355             s.push(cd);
       
   356             TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass()));
       
   357             if (c == null)
       
   358                 break;
       
   359             cd = c;
       
   360         }
       
   361 
       
   362         while (!s.empty()) {
       
   363             cd = s.pop();
       
   364             fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements()));
       
   365         }
       
   366 
       
   367         return fields;
       
   368     }
       
   369 
       
   370     // c.f. MethodDoc.signature
       
   371     String signature(ExecutableElement e) {
       
   372         StringBuilder sb = new StringBuilder("(");
       
   373         String sep = "";
       
   374         for (VariableElement p: e.getParameters()) {
       
   375             sb.append(sep);
       
   376             sb.append(types.erasure(p.asType()).toString());
       
   377             sep = ",";
       
   378         }
       
   379         sb.append(")");
       
   380         return sb.toString();
       
   381     }
       
   382 }
       
   383