Mon, 26 Mar 2012 15:27:51 +0100
7151580: Separate DA/DU logic from exception checking logic in Flow.java
Summary: DA/DU analysis and exception checking analysis should live in two separate tree visitors
Reviewed-by: gafter, dlsmith, 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 supported API.
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 }