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

changeset 416
c287d51c57da
parent 229
03bcd66bd8e7
child 554
9d9f26857129
equal deleted inserted replaced
415:49359d0e6a9c 416:c287d51c57da
25 25
26 package com.sun.tools.javah; 26 package com.sun.tools.javah;
27 27
28 import java.io.UnsupportedEncodingException; 28 import java.io.UnsupportedEncodingException;
29 import java.io.ByteArrayOutputStream; 29 import java.io.ByteArrayOutputStream;
30 import java.io.FileNotFoundException;
30 import java.io.IOException; 31 import java.io.IOException;
32 import java.io.InputStream;
31 import java.io.OutputStream; 33 import java.io.OutputStream;
34 import java.io.OutputStreamWriter;
32 import java.io.PrintWriter; 35 import java.io.PrintWriter;
33 import com.sun.javadoc.*; 36 import java.util.ArrayList;
34 import java.io.*; 37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Set;
35 import java.util.Stack; 40 import java.util.Stack;
36 import java.util.Vector; 41
37 import java.util.Arrays; 42 import javax.annotation.processing.ProcessingEnvironment;
38 43
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
52 import javax.tools.FileObject;
53 import javax.tools.JavaFileManager;
54 import javax.tools.JavaFileObject;
55 import javax.tools.StandardLocation;
39 56
40 /** 57 /**
41 * An abstraction for generating support files required by native methods. 58 * An abstraction for generating support files required by native methods.
42 * Subclasses are for specific native interfaces. At the time of its 59 * Subclasses are for specific native interfaces. At the time of its
43 * original writing, this interface is rich enough to support JNI and the 60 * original writing, this interface is rich enough to support JNI and the
44 * old 1.0-style native method interface. 61 * old 1.0-style native method interface.
45 * 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 *
46 * @author Sucheta Dambalkar(Revised) 68 * @author Sucheta Dambalkar(Revised)
47 */ 69 */
48
49
50 public abstract class Gen { 70 public abstract class Gen {
51 protected String lineSep = System.getProperty("line.separator"); 71 protected String lineSep = System.getProperty("line.separator");
52 72
53 RootDoc root; 73 protected ProcessingEnvironment processingEnvironment;
74 protected Types types;
75 protected Elements elems;
76 protected Mangle mangler;
77 protected Util util;
78
79 protected Gen(Util util) {
80 this.util = util;
81 }
82
54 /* 83 /*
55 * List of classes for which we must generate output. 84 * List of classes for which we must generate output.
56 */ 85 */
57 protected ClassDoc[] classes; 86 protected Set<TypeElement> classes;
58 static private final boolean isWindows = 87 static private final boolean isWindows =
59 System.getProperty("os.name").startsWith("Windows"); 88 System.getProperty("os.name").startsWith("Windows");
60 89
61 public Gen(RootDoc root){
62 this.root = root;
63 }
64 90
65 /** 91 /**
66 * Override this abstract method, generating content for the named 92 * Override this abstract method, generating content for the named
67 * class into the outputstream. 93 * class into the outputstream.
68 */ 94 */
69 protected abstract void write(OutputStream o, ClassDoc clazz) 95 protected abstract void write(OutputStream o, TypeElement clazz) throws Util.Exit;
70 throws ClassNotFoundException;
71 96
72 /** 97 /**
73 * Override this method to provide a list of #include statements 98 * Override this method to provide a list of #include statements
74 * required by the native interface. 99 * required by the native interface.
75 */ 100 */
76 protected abstract String getIncludes(); 101 protected abstract String getIncludes();
77 102
78 /* 103 /*
79 * Output location. 104 * Output location.
80 */ 105 */
81 protected String outDir; 106 protected JavaFileManager fileManager;
82 protected String outFile; 107 protected JavaFileObject outFile;
83 108
84 public void setOutDir(String outDir) { 109 public void setFileManager(JavaFileManager fm) {
85 /* Check important, otherwise concatenation of two null strings 110 fileManager = fm;
86 * produces the "nullnull" String. 111 }
87 */ 112
88 if (outDir != null) { 113 public void setOutFile(JavaFileObject outFile) {
89 this.outDir = outDir + System.getProperty("file.separator");
90 File d = new File(outDir);
91 if (!d.exists())
92 if (!d.mkdirs())
93 Util.error("cant.create.dir", d.toString());
94 }
95 }
96
97 public void setOutFile(String outFile) {
98 this.outFile = outFile; 114 this.outFile = outFile;
99 } 115 }
100 116
101 117
102 public void setClasses(ClassDoc[] classes) { 118 public void setClasses(Set<TypeElement> classes) {
103 this.classes = classes; 119 this.classes = classes;
120 }
121
122 void setProcessingEnvironment(ProcessingEnvironment pEnv) {
123 processingEnvironment = pEnv;
124 elems = pEnv.getElementUtils();
125 types = pEnv.getTypeUtils();
126 mangler = new Mangle(elems, types);
104 } 127 }
105 128
106 /* 129 /*
107 * Smartness with generated files. 130 * Smartness with generated files.
108 */ 131 */
114 137
115 /** 138 /**
116 * We explicitly need to write ASCII files because that is what C 139 * We explicitly need to write ASCII files because that is what C
117 * compilers understand. 140 * compilers understand.
118 */ 141 */
119 protected PrintWriter wrapWriter(OutputStream o) { 142 protected PrintWriter wrapWriter(OutputStream o) throws Util.Exit {
120 try { 143 try {
121 return new 144 return new PrintWriter(new OutputStreamWriter(o, "ISO8859_1"), true);
122 PrintWriter(new OutputStreamWriter(o, "ISO8859_1"), true);
123 } catch (UnsupportedEncodingException use) { 145 } catch (UnsupportedEncodingException use) {
124 Util.bug("encoding.iso8859_1.not.found"); 146 util.bug("encoding.iso8859_1.not.found");
125 return null; /* dead code */ 147 return null; /* dead code */
126 } 148 }
127 } 149 }
128 150
129 /** 151 /**
131 * processing. 153 * processing.
132 * 154 *
133 * Buffer size chosen as an approximation from a single sampling of: 155 * Buffer size chosen as an approximation from a single sampling of:
134 * expr `du -sk` / `ls *.h | wc -l` 156 * expr `du -sk` / `ls *.h | wc -l`
135 */ 157 */
136 public void run() throws IOException, ClassNotFoundException { 158 public void run() throws IOException, ClassNotFoundException, Util.Exit {
137 int i = 0; 159 int i = 0;
138 if (outFile != null) { 160 if (outFile != null) {
139 /* Everything goes to one big file... */ 161 /* Everything goes to one big file... */
140 ByteArrayOutputStream bout = new ByteArrayOutputStream(8192); 162 ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
141 writeFileTop(bout); /* only once */ 163 writeFileTop(bout); /* only once */
142 164
143 for (i = 0; i < classes.length; i++) { 165 for (TypeElement t: classes) {
144 write(bout, classes[i]); 166 write(bout, t);
145 } 167 }
146 168
147 writeIfChanged(bout.toByteArray(), outFile); 169 writeIfChanged(bout.toByteArray(), outFile);
148 } else { 170 } else {
149 /* Each class goes to its own file... */ 171 /* Each class goes to its own file... */
150 for (i = 0; i < classes.length; i++) { 172 for (TypeElement t: classes) {
151 ByteArrayOutputStream bout = new ByteArrayOutputStream(8192); 173 ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
152 writeFileTop(bout); 174 writeFileTop(bout);
153 ClassDoc clazz = classes[i]; 175 write(bout, t);
154 write(bout, clazz); 176 writeIfChanged(bout.toByteArray(), getFileObject(t.getQualifiedName()));
155 writeIfChanged(bout.toByteArray(), getFileName(clazz.qualifiedName()));
156 } 177 }
157 } 178 }
158 } 179 }
159 180
160 /* 181 /*
161 * Write the contents of byte[] b to a file named file. Writing 182 * Write the contents of byte[] b to a file named file. Writing
162 * is done if either the file doesn't exist or if the contents are 183 * is done if either the file doesn't exist or if the contents are
163 * different. 184 * different.
164 */ 185 */
165 private void writeIfChanged(byte[] b, String file) throws IOException { 186 private void writeIfChanged(byte[] b, FileObject file) throws IOException {
166 File f = new File(file);
167 boolean mustWrite = false; 187 boolean mustWrite = false;
168 String event = "[No need to update file "; 188 String event = "[No need to update file ";
169 189
170 if (force) { 190 if (force) {
171 mustWrite = true; 191 mustWrite = true;
172 event = "[Forcefully writing file "; 192 event = "[Forcefully writing file ";
173 } else { 193 } else {
174 if (!f.exists()) { 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 ";
205
206 }
207 } catch (FileNotFoundException e) {
175 mustWrite = true; 208 mustWrite = true;
176 event = "[Creating file "; 209 event = "[Creating file ";
177 } else { 210 }
178 int l = (int)f.length(); 211 }
179 if (b.length != l) { 212
180 mustWrite = true; 213 if (util.verbose)
181 event = "[Overwriting file "; 214 util.log(event + file + "]");
182 } else { 215
183 /* Lengths are equal, so read it. */
184 byte[] a = new byte[l];
185 FileInputStream in = new FileInputStream(f);
186 if (in.read(a) != l) {
187 in.close();
188 /* This can't happen, we already checked the length. */
189 Util.error("not.enough.bytes", Integer.toString(l),
190 f.toString());
191 }
192 in.close();
193 while (--l >= 0) {
194 if (a[l] != b[l]) {
195 mustWrite = true;
196 event = "[Overwriting file ";
197 }
198 }
199 }
200 }
201 }
202 if (Util.verbose)
203 Util.log(event + file + "]");
204 if (mustWrite) { 216 if (mustWrite) {
205 OutputStream out = new FileOutputStream(file); 217 OutputStream out = file.openOutputStream();
206 out.write(b); /* No buffering, just one big write! */ 218 out.write(b); /* No buffering, just one big write! */
207 out.close(); 219 out.close();
208 } 220 }
209 } 221 }
210 222
211 protected String defineForStatic(ClassDoc c, FieldDoc f){ 223 protected byte[] readBytes(InputStream in) throws IOException {
212 224 try {
213 String cnamedoc = c.qualifiedName(); 225 byte[] array = new byte[in.available() + 1];
214 String fnamedoc = f.name(); 226 int offset = 0;
215 227 int n;
216 String cname = Mangle.mangle(cnamedoc, Mangle.Type.CLASS); 228 while ((n = in.read(array, offset, array.length - offset)) != -1) {
217 String fname = Mangle.mangle(fnamedoc, Mangle.Type.FIELDSTUB); 229 offset += n;
218 230 if (offset == array.length)
219 if (!f.isStatic()) 231 array = Arrays.copyOf(array, array.length * 2);
220 Util.bug("tried.to.define.non.static"); 232 }
221 233
222 if (f.isFinal()) { 234 return Arrays.copyOf(array, offset);
235 } finally {
236 in.close();
237 }
238 }
239
240 protected String defineForStatic(TypeElement c, VariableElement f)
241 throws Util.Exit {
242 CharSequence cnamedoc = c.getQualifiedName();
243 CharSequence fnamedoc = f.getSimpleName();
244
245 String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS);
246 String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
247
248 if (!f.getModifiers().contains(Modifier.STATIC))
249 util.bug("tried.to.define.non.static");
250
251 if (f.getModifiers().contains(Modifier.FINAL)) {
223 Object value = null; 252 Object value = null;
224 253
225 value = f.constantValue(); 254 value = f.getConstantValue();
226 255
227 if (value != null) { /* so it is a ConstantExpression */ 256 if (value != null) { /* so it is a ConstantExpression */
228 String constString = null; 257 String constString = null;
229 if ((value instanceof Integer) 258 if ((value instanceof Integer)
230 || (value instanceof Byte) 259 || (value instanceof Byte)
231 || (value instanceof Character) 260 || (value instanceof Short)) {
232 || (value instanceof Short) 261 /* covers byte, short, int */
233 || (value instanceof Boolean)) { 262 constString = value.toString() + "L";
234 /* covers byte, boolean, char, short, int */ 263 } else if (value instanceof Boolean) {
235 if(value instanceof Boolean) 264 constString = ((Boolean) value) ? "1L" : "0L";
236 constString = (value.toString() == "true") ? "1L" : "0L"; 265 } else if (value instanceof Character) {
237 else 266 Character ch = (Character) value;
238 constString = value.toString() + "L"; 267 constString = String.valueOf(((int) ch) & 0xffff) + "L";
239 } else if (value instanceof Long) { 268 } else if (value instanceof Long) {
240 // Visual C++ supports the i64 suffix, not LL. 269 // Visual C++ supports the i64 suffix, not LL.
241 if (isWindows) 270 if (isWindows)
242 constString = value.toString() + "i64"; 271 constString = value.toString() + "i64";
243 else 272 else
292 } 321 }
293 322
294 /* 323 /*
295 * File name and file preamble related operations. 324 * File name and file preamble related operations.
296 */ 325 */
297 protected void writeFileTop(OutputStream o) { 326 protected void writeFileTop(OutputStream o) throws Util.Exit {
298 PrintWriter pw = wrapWriter(o); 327 PrintWriter pw = wrapWriter(o);
299 pw.println("/* DO NOT EDIT THIS FILE - it is machine generated */" + lineSep + 328 pw.println("/* DO NOT EDIT THIS FILE - it is machine generated */" + lineSep +
300 getIncludes()); 329 getIncludes());
301 } 330 }
302 331
303 protected String baseFileName(String clazz) { 332 protected String baseFileName(CharSequence className) {
304 StringBuffer f = 333 return mangler.mangle(className, Mangle.Type.CLASS);
305 new StringBuffer(Mangle.mangle(clazz, 334 }
306 Mangle.Type.CLASS)); 335
307 if (outDir != null) { 336 protected FileObject getFileObject(CharSequence className) throws IOException {
308 f.insert(0, outDir); 337 String name = baseFileName(className) + getFileSuffix();
309 } 338 return fileManager.getFileForOutput(StandardLocation.SOURCE_OUTPUT, "", name, null);
310 return f.toString();
311 }
312
313 protected String getFileName(String clazz) {
314 return baseFileName(clazz) + getFileSuffix();
315 } 339 }
316 340
317 protected String getFileSuffix() { 341 protected String getFileSuffix() {
318 return ".h"; 342 return ".h";
319 } 343 }
320 344
321 /** 345 /**
322 * Including super classes' fields. 346 * Including super classes' fields.
323 */ 347 */
324 348
325 FieldDoc[] getAllFields(ClassDoc subclazz) 349 List<VariableElement> getAllFields(TypeElement subclazz) {
326 throws ClassNotFoundException { 350 List<VariableElement> fields = new ArrayList<VariableElement>();
327 Vector<FieldDoc> fields = new Vector<FieldDoc>(); 351 TypeElement cd = null;
328 ClassDoc cd = null; 352 Stack<TypeElement> s = new Stack<TypeElement>();
329 Stack<Object> s = new Stack<Object>();
330 353
331 cd = subclazz; 354 cd = subclazz;
332 while (true) { 355 while (true) {
333 s.push(cd); 356 s.push(cd);
334 ClassDoc c = cd.superclass(); 357 TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass()));
335 if (c == null) 358 if (c == null)
336 break; 359 break;
337 cd = c; 360 cd = c;
338 } 361 }
339 362
340 while (!s.empty()) { 363 while (!s.empty()) {
341 cd = (ClassDoc)s.pop(); 364 cd = s.pop();
342 fields.addAll(Arrays.asList(cd.fields())); 365 fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements()));
343 } 366 }
344 367
345 return fields.toArray(new FieldDoc[fields.size()]); 368 return fields;
369 }
370
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();
346 } 382 }
347 } 383 }
384

mercurial