PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

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

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