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

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

mercurial