src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java

Sun, 17 Feb 2013 16:44:55 -0500

author
dholmes
date
Sun, 17 Feb 2013 16:44:55 -0500
changeset 1571
af8417e590f4
parent 1521
71f35e4b93a5
child 1723
a2889739cf21
permissions
-rw-r--r--

Merge

jjg@1230 1 /*
jjg@1521 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
jjg@1230 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@1230 4 *
jjg@1230 5 * This code is free software; you can redistribute it and/or modify it
jjg@1230 6 * under the terms of the GNU General Public License version 2 only, as
jjg@1230 7 * published by the Free Software Foundation. Oracle designates this
jjg@1230 8 * particular file as subject to the "Classpath" exception as provided
jjg@1230 9 * by Oracle in the LICENSE file that accompanied this code.
jjg@1230 10 *
jjg@1230 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@1230 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@1230 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@1230 14 * version 2 for more details (a copy is included in the LICENSE file that
jjg@1230 15 * accompanied this code).
jjg@1230 16 *
jjg@1230 17 * You should have received a copy of the GNU General Public License version
jjg@1230 18 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@1230 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@1230 20 *
jjg@1230 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jjg@1230 22 * or visit www.oracle.com if you need additional information or have any
jjg@1230 23 * questions.
jjg@1230 24 */
jjg@1230 25
jjg@1230 26 package com.sun.tools.javac.jvm;
jjg@1230 27
jjg@1230 28 import java.io.IOException;
jjg@1230 29 import java.io.Writer;
jjg@1230 30 import java.util.ArrayList;
jjg@1230 31 import java.util.List;
jjg@1230 32 import java.util.Stack;
jjg@1230 33 import java.util.StringTokenizer;
jjg@1230 34
jjg@1230 35 import javax.lang.model.element.Element;
jjg@1230 36 import javax.lang.model.element.ExecutableElement;
jjg@1230 37 import javax.lang.model.element.Modifier;
jjg@1230 38 import javax.lang.model.element.Name;
jjg@1230 39 import javax.lang.model.element.TypeElement;
jjg@1230 40 import javax.lang.model.element.VariableElement;
jjg@1230 41 import javax.lang.model.type.ArrayType;
jjg@1230 42 import javax.lang.model.type.DeclaredType;
jjg@1230 43 import javax.lang.model.type.NoType;
jjg@1230 44 import javax.lang.model.type.PrimitiveType;
jjg@1230 45 import javax.lang.model.type.TypeKind;
jjg@1230 46 import javax.lang.model.type.TypeMirror;
jjg@1230 47 import javax.lang.model.type.TypeVariable;
jjg@1230 48 import javax.lang.model.type.TypeVisitor;
jjg@1230 49 import javax.lang.model.util.ElementFilter;
jjg@1230 50 import javax.lang.model.util.Elements;
jjg@1230 51 import javax.lang.model.util.SimpleTypeVisitor8;
jjg@1230 52 import javax.lang.model.util.Types;
jjg@1230 53
jjg@1230 54 import javax.tools.FileObject;
jjg@1230 55 import javax.tools.JavaFileManager;
jjg@1230 56 import javax.tools.StandardLocation;
jjg@1230 57
jjg@1230 58 import com.sun.tools.javac.code.Attribute;
jjg@1230 59 import com.sun.tools.javac.code.Flags;
jjg@1230 60 import com.sun.tools.javac.code.Kinds;
jjg@1230 61 import com.sun.tools.javac.code.Scope;
jjg@1230 62 import com.sun.tools.javac.code.Symbol.ClassSymbol;
jjg@1230 63 import com.sun.tools.javac.code.Symtab;
jjg@1230 64 import com.sun.tools.javac.model.JavacElements;
jjg@1230 65 import com.sun.tools.javac.model.JavacTypes;
jjg@1230 66 import com.sun.tools.javac.util.Assert;
jjg@1230 67 import com.sun.tools.javac.util.Context;
jjg@1230 68 import com.sun.tools.javac.util.Log;
jjg@1230 69 import com.sun.tools.javac.util.Options;
jjg@1230 70
jjg@1230 71 import static com.sun.tools.javac.main.Option.*;
jjg@1230 72
jjg@1230 73 /** This class provides operations to write native header files for classes.
jjg@1230 74 *
jjg@1230 75 * <p><b>This is NOT part of any supported API.
jjg@1230 76 * If you write code that depends on this, you do so at your own risk.
jjg@1230 77 * This code and its internal interfaces are subject to change or
jjg@1230 78 * deletion without notice.</b>
jjg@1230 79 */
jjg@1230 80 public class JNIWriter {
jjg@1230 81 protected static final Context.Key<JNIWriter> jniWriterKey =
jjg@1230 82 new Context.Key<JNIWriter>();
jjg@1230 83
jjg@1230 84 /** Access to files. */
jjg@1230 85 private final JavaFileManager fileManager;
jjg@1230 86
jjg@1230 87 JavacElements elements;
jjg@1230 88 JavacTypes types;
jjg@1230 89
jjg@1230 90 /** The log to use for verbose output.
jjg@1230 91 */
jjg@1230 92 private final Log log;
jjg@1230 93
jjg@1230 94 /** Switch: verbose output.
jjg@1230 95 */
jjg@1230 96 private boolean verbose;
jjg@1230 97
jjg@1230 98 /** Switch: check all nested classes of top level class
jjg@1230 99 */
jjg@1230 100 private boolean checkAll;
jjg@1230 101
jjg@1230 102 private Mangle mangler;
jjg@1230 103
jjg@1230 104 private Context context;
jjg@1230 105
jjg@1230 106 private Symtab syms;
jjg@1230 107
jjg@1230 108 private String lineSep;
jjg@1230 109
jjg@1230 110 private final boolean isWindows =
jjg@1230 111 System.getProperty("os.name").startsWith("Windows");
jjg@1230 112
jjg@1230 113 /** Get the ClassWriter instance for this context. */
jjg@1230 114 public static JNIWriter instance(Context context) {
jjg@1230 115 JNIWriter instance = context.get(jniWriterKey);
jjg@1230 116 if (instance == null)
jjg@1230 117 instance = new JNIWriter(context);
jjg@1230 118 return instance;
jjg@1230 119 }
jjg@1230 120
jjg@1230 121 /** Construct a class writer, given an options table.
jjg@1230 122 */
jjg@1230 123 private JNIWriter(Context context) {
jjg@1230 124 context.put(jniWriterKey, this);
jjg@1230 125 fileManager = context.get(JavaFileManager.class);
jjg@1230 126 log = Log.instance(context);
jjg@1230 127
jjg@1230 128 Options options = Options.instance(context);
jjg@1230 129 verbose = options.isSet(VERBOSE);
jjg@1230 130 checkAll = options.isSet("javah:full");
jjg@1230 131
jjg@1230 132 this.context = context; // for lazyInit()
jjg@1230 133 syms = Symtab.instance(context);
jjg@1230 134
jjg@1230 135 lineSep = System.getProperty("line.separator");
jjg@1230 136 }
jjg@1230 137
jjg@1230 138 private void lazyInit() {
jjg@1230 139 if (mangler == null) {
jjg@1230 140 elements = JavacElements.instance(context);
jjg@1230 141 types = JavacTypes.instance(context);
jjg@1230 142 mangler = new Mangle(elements, types);
jjg@1230 143 }
jjg@1230 144 }
jjg@1230 145
jjg@1230 146 public boolean needsHeader(ClassSymbol c) {
jjg@1230 147 if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0)
jjg@1230 148 return false;
jjg@1230 149
jjg@1230 150 if (checkAll)
jjg@1230 151 return needsHeader(c.outermostClass(), true);
jjg@1230 152 else
jjg@1230 153 return needsHeader(c, false);
jjg@1230 154 }
jjg@1230 155
jjg@1230 156 private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) {
jjg@1230 157 if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0)
jjg@1230 158 return false;
jjg@1230 159
jjg@1407 160 /* temporary code for backwards compatibility */
jjg@1521 161 for (Attribute.Compound a: c.annotations.getDeclarationAttributes()) {
jjg@1407 162 if (a.type.tsym == syms.nativeHeaderType_old.tsym)
jjg@1230 163 return true;
jjg@1230 164 }
jjg@1407 165 /* end of temporary code for backwards compatibility */
jjg@1407 166
jjg@1230 167 for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) {
jjg@1230 168 if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0)
jjg@1230 169 return true;
jjg@1521 170 for (Attribute.Compound a: i.sym.annotations.getDeclarationAttributes()) {
jjg@1407 171 if (a.type.tsym == syms.nativeHeaderType.tsym)
jjg@1407 172 return true;
jjg@1407 173 }
jjg@1230 174 }
jjg@1230 175 if (checkNestedClasses) {
jjg@1230 176 for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) {
jjg@1230 177 if ((i.sym.kind == Kinds.TYP) && needsHeader(((ClassSymbol) i.sym), true))
jjg@1230 178 return true;
jjg@1230 179 }
jjg@1230 180 }
jjg@1230 181 return false;
jjg@1230 182 }
jjg@1230 183
jjg@1230 184 /** Emit a class file for a given class.
jjg@1230 185 * @param c The class from which a class file is generated.
jjg@1230 186 */
jjg@1230 187 public FileObject write(ClassSymbol c)
jjg@1230 188 throws IOException
jjg@1230 189 {
jjg@1230 190 String className = c.flatName().toString();
jjg@1230 191 FileObject outFile
jjg@1230 192 = fileManager.getFileForOutput(StandardLocation.NATIVE_HEADER_OUTPUT,
jjg@1230 193 "", className.replaceAll("[.$]", "_") + ".h", null);
jjg@1230 194 Writer out = outFile.openWriter();
jjg@1230 195 try {
jjg@1230 196 write(out, c);
jjg@1230 197 if (verbose)
jjg@1230 198 log.printVerbose("wrote.file", outFile);
jjg@1230 199 out.close();
jjg@1230 200 out = null;
jjg@1230 201 } finally {
jjg@1230 202 if (out != null) {
jjg@1230 203 // if we are propogating an exception, delete the file
jjg@1230 204 out.close();
jjg@1230 205 outFile.delete();
jjg@1230 206 outFile = null;
jjg@1230 207 }
jjg@1230 208 }
jjg@1230 209 return outFile; // may be null if write failed
jjg@1230 210 }
jjg@1230 211
jjg@1230 212 public void write(Writer out, ClassSymbol sym)
jjg@1230 213 throws IOException {
jjg@1230 214 lazyInit();
jjg@1230 215 try {
jjg@1230 216 String cname = mangler.mangle(sym.fullname, Mangle.Type.CLASS);
jjg@1230 217 println(out, fileTop());
jjg@1230 218 println(out, includes());
jjg@1230 219 println(out, guardBegin(cname));
jjg@1230 220 println(out, cppGuardBegin());
jjg@1230 221
jjg@1230 222 writeStatics(out, sym);
jjg@1230 223 writeMethods(out, sym, cname);
jjg@1230 224
jjg@1230 225 println(out, cppGuardEnd());
jjg@1230 226 println(out, guardEnd(cname));
jjg@1230 227 } catch (TypeSignature.SignatureException e) {
jjg@1230 228 throw new IOException(e);
jjg@1230 229 }
jjg@1230 230 }
jjg@1230 231
jjg@1230 232 protected void writeStatics(Writer out, ClassSymbol sym) throws IOException {
jjg@1230 233 List<VariableElement> classfields = getAllFields(sym);
jjg@1230 234
jjg@1230 235 for (VariableElement v: classfields) {
jjg@1230 236 if (!v.getModifiers().contains(Modifier.STATIC))
jjg@1230 237 continue;
jjg@1230 238 String s = null;
jjg@1230 239 s = defineForStatic(sym, v);
jjg@1230 240 if (s != null) {
jjg@1230 241 println(out, s);
jjg@1230 242 }
jjg@1230 243 }
jjg@1230 244 }
jjg@1230 245
jjg@1230 246 /**
jjg@1230 247 * Including super class fields.
jjg@1230 248 */
jjg@1230 249 List<VariableElement> getAllFields(TypeElement subclazz) {
jjg@1230 250 List<VariableElement> fields = new ArrayList<VariableElement>();
jjg@1230 251 TypeElement cd = null;
jjg@1230 252 Stack<TypeElement> s = new Stack<TypeElement>();
jjg@1230 253
jjg@1230 254 cd = subclazz;
jjg@1230 255 while (true) {
jjg@1230 256 s.push(cd);
jjg@1230 257 TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass()));
jjg@1230 258 if (c == null)
jjg@1230 259 break;
jjg@1230 260 cd = c;
jjg@1230 261 }
jjg@1230 262
jjg@1230 263 while (!s.empty()) {
jjg@1230 264 cd = s.pop();
jjg@1230 265 fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements()));
jjg@1230 266 }
jjg@1230 267
jjg@1230 268 return fields;
jjg@1230 269 }
jjg@1230 270
jjg@1230 271 protected String defineForStatic(TypeElement c, VariableElement f) {
jjg@1230 272 CharSequence cnamedoc = c.getQualifiedName();
jjg@1230 273 CharSequence fnamedoc = f.getSimpleName();
jjg@1230 274
jjg@1230 275 String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS);
jjg@1230 276 String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
jjg@1230 277
jjg@1230 278 Assert.check(f.getModifiers().contains(Modifier.STATIC));
jjg@1230 279
jjg@1230 280 if (f.getModifiers().contains(Modifier.FINAL)) {
jjg@1230 281 Object value = null;
jjg@1230 282
jjg@1230 283 value = f.getConstantValue();
jjg@1230 284
jjg@1230 285 if (value != null) { /* so it is a ConstantExpression */
jjg@1230 286 String constString = null;
jjg@1230 287 if ((value instanceof Integer)
jjg@1230 288 || (value instanceof Byte)
jjg@1230 289 || (value instanceof Short)) {
jjg@1230 290 /* covers byte, short, int */
jjg@1230 291 constString = value.toString() + "L";
jjg@1230 292 } else if (value instanceof Boolean) {
jjg@1230 293 constString = ((Boolean) value) ? "1L" : "0L";
jjg@1230 294 } else if (value instanceof Character) {
jjg@1230 295 Character ch = (Character) value;
jjg@1230 296 constString = String.valueOf(((int) ch) & 0xffff) + "L";
jjg@1230 297 } else if (value instanceof Long) {
jjg@1230 298 // Visual C++ supports the i64 suffix, not LL.
jjg@1230 299 if (isWindows)
jjg@1230 300 constString = value.toString() + "i64";
jjg@1230 301 else
jjg@1230 302 constString = value.toString() + "LL";
jjg@1230 303 } else if (value instanceof Float) {
jjg@1230 304 /* bug for bug */
jjg@1230 305 float fv = ((Float)value).floatValue();
jjg@1230 306 if (Float.isInfinite(fv))
jjg@1230 307 constString = ((fv < 0) ? "-" : "") + "Inff";
jjg@1230 308 else
jjg@1230 309 constString = value.toString() + "f";
jjg@1230 310 } else if (value instanceof Double) {
jjg@1230 311 /* bug for bug */
jjg@1230 312 double d = ((Double)value).doubleValue();
jjg@1230 313 if (Double.isInfinite(d))
jjg@1230 314 constString = ((d < 0) ? "-" : "") + "InfD";
jjg@1230 315 else
jjg@1230 316 constString = value.toString();
jjg@1230 317 }
jjg@1230 318
jjg@1230 319 if (constString != null) {
jjg@1230 320 StringBuilder s = new StringBuilder("#undef ");
jjg@1230 321 s.append(cname); s.append("_"); s.append(fname); s.append(lineSep);
jjg@1230 322 s.append("#define "); s.append(cname); s.append("_");
jjg@1230 323 s.append(fname); s.append(" "); s.append(constString);
jjg@1230 324 return s.toString();
jjg@1230 325 }
jjg@1230 326
jjg@1230 327 }
jjg@1230 328 }
jjg@1230 329
jjg@1230 330 return null;
jjg@1230 331 }
jjg@1230 332
jjg@1230 333
jjg@1230 334 protected void writeMethods(Writer out, ClassSymbol sym, String cname)
jjg@1230 335 throws IOException, TypeSignature.SignatureException {
jjg@1230 336 List<ExecutableElement> classmethods = ElementFilter.methodsIn(sym.getEnclosedElements());
jjg@1230 337 for (ExecutableElement md: classmethods) {
jjg@1230 338 if(md.getModifiers().contains(Modifier.NATIVE)){
jjg@1230 339 TypeMirror mtr = types.erasure(md.getReturnType());
jjg@1230 340 String sig = signature(md);
jjg@1230 341 TypeSignature newtypesig = new TypeSignature(elements);
jjg@1230 342 CharSequence methodName = md.getSimpleName();
jjg@1230 343 boolean longName = false;
jjg@1230 344 for (ExecutableElement md2: classmethods) {
jjg@1230 345 if ((md2 != md)
jjg@1230 346 && (methodName.equals(md2.getSimpleName()))
jjg@1230 347 && (md2.getModifiers().contains(Modifier.NATIVE)))
jjg@1230 348 longName = true;
jjg@1230 349
jjg@1230 350 }
jjg@1230 351 println(out, "/*");
jjg@1230 352 println(out, " * Class: " + cname);
jjg@1230 353 println(out, " * Method: " +
jjg@1230 354 mangler.mangle(methodName, Mangle.Type.FIELDSTUB));
jjg@1230 355 println(out, " * Signature: " + newtypesig.getTypeSignature(sig, mtr));
jjg@1230 356 println(out, " */");
jjg@1230 357 println(out, "JNIEXPORT " + jniType(mtr) +
jjg@1230 358 " JNICALL " +
jjg@1230 359 mangler.mangleMethod(md, sym,
jjg@1230 360 (longName) ?
jjg@1230 361 Mangle.Type.METHOD_JNI_LONG :
jjg@1230 362 Mangle.Type.METHOD_JNI_SHORT));
jjg@1230 363 print(out, " (JNIEnv *, ");
jjg@1230 364 List<? extends VariableElement> paramargs = md.getParameters();
jjg@1230 365 List<TypeMirror> args = new ArrayList<TypeMirror>();
jjg@1230 366 for (VariableElement p: paramargs) {
jjg@1230 367 args.add(types.erasure(p.asType()));
jjg@1230 368 }
jjg@1230 369 if (md.getModifiers().contains(Modifier.STATIC))
jjg@1230 370 print(out, "jclass");
jjg@1230 371 else
jjg@1230 372 print(out, "jobject");
jjg@1230 373
jjg@1230 374 for (TypeMirror arg: args) {
jjg@1230 375 print(out, ", ");
jjg@1230 376 print(out, jniType(arg));
jjg@1230 377 }
jjg@1230 378 println(out, ");"
jjg@1230 379 + lineSep);
jjg@1230 380 }
jjg@1230 381 }
jjg@1230 382 }
jjg@1230 383
jjg@1230 384 // c.f. MethodDoc.signature
jjg@1230 385 String signature(ExecutableElement e) {
jjg@1230 386 StringBuilder sb = new StringBuilder("(");
jjg@1230 387 String sep = "";
jjg@1230 388 for (VariableElement p: e.getParameters()) {
jjg@1230 389 sb.append(sep);
jjg@1230 390 sb.append(types.erasure(p.asType()).toString());
jjg@1230 391 sep = ",";
jjg@1230 392 }
jjg@1230 393 sb.append(")");
jjg@1230 394 return sb.toString();
jjg@1230 395 }
jjg@1230 396
jjg@1230 397 protected final String jniType(TypeMirror t) {
jjg@1230 398 TypeElement throwable = elements.getTypeElement("java.lang.Throwable");
jjg@1230 399 TypeElement jClass = elements.getTypeElement("java.lang.Class");
jjg@1230 400 TypeElement jString = elements.getTypeElement("java.lang.String");
jjg@1230 401 Element tclassDoc = types.asElement(t);
jjg@1230 402
jjg@1230 403
jjg@1230 404 switch (t.getKind()) {
jjg@1230 405 case ARRAY: {
jjg@1230 406 TypeMirror ct = ((ArrayType) t).getComponentType();
jjg@1230 407 switch (ct.getKind()) {
jjg@1230 408 case BOOLEAN: return "jbooleanArray";
jjg@1230 409 case BYTE: return "jbyteArray";
jjg@1230 410 case CHAR: return "jcharArray";
jjg@1230 411 case SHORT: return "jshortArray";
jjg@1230 412 case INT: return "jintArray";
jjg@1230 413 case LONG: return "jlongArray";
jjg@1230 414 case FLOAT: return "jfloatArray";
jjg@1230 415 case DOUBLE: return "jdoubleArray";
jjg@1230 416 case ARRAY:
jjg@1230 417 case DECLARED: return "jobjectArray";
jjg@1230 418 default: throw new Error(ct.toString());
jjg@1230 419 }
jjg@1230 420 }
jjg@1230 421
jjg@1230 422 case VOID: return "void";
jjg@1230 423 case BOOLEAN: return "jboolean";
jjg@1230 424 case BYTE: return "jbyte";
jjg@1230 425 case CHAR: return "jchar";
jjg@1230 426 case SHORT: return "jshort";
jjg@1230 427 case INT: return "jint";
jjg@1230 428 case LONG: return "jlong";
jjg@1230 429 case FLOAT: return "jfloat";
jjg@1230 430 case DOUBLE: return "jdouble";
jjg@1230 431
jjg@1230 432 case DECLARED: {
jjg@1230 433 if (tclassDoc.equals(jString))
jjg@1230 434 return "jstring";
jjg@1230 435 else if (types.isAssignable(t, throwable.asType()))
jjg@1230 436 return "jthrowable";
jjg@1230 437 else if (types.isAssignable(t, jClass.asType()))
jjg@1230 438 return "jclass";
jjg@1230 439 else
jjg@1230 440 return "jobject";
jjg@1230 441 }
jjg@1230 442 }
jjg@1230 443
jjg@1230 444 Assert.check(false, "jni unknown type");
jjg@1230 445 return null; /* dead code. */
jjg@1230 446 }
jjg@1230 447
jjg@1230 448 protected String fileTop() {
jjg@1230 449 return "/* DO NOT EDIT THIS FILE - it is machine generated */";
jjg@1230 450 }
jjg@1230 451
jjg@1230 452 protected String includes() {
jjg@1230 453 return "#include <jni.h>";
jjg@1230 454 }
jjg@1230 455
jjg@1230 456 /*
jjg@1230 457 * Deal with the C pre-processor.
jjg@1230 458 */
jjg@1230 459 protected String cppGuardBegin() {
jjg@1230 460 return "#ifdef __cplusplus" + lineSep
jjg@1230 461 + "extern \"C\" {" + lineSep
jjg@1230 462 + "#endif";
jjg@1230 463 }
jjg@1230 464
jjg@1230 465 protected String cppGuardEnd() {
jjg@1230 466 return "#ifdef __cplusplus" + lineSep
jjg@1230 467 + "}" + lineSep
jjg@1230 468 + "#endif";
jjg@1230 469 }
jjg@1230 470
jjg@1230 471 protected String guardBegin(String cname) {
jjg@1230 472 return "/* Header for class " + cname + " */" + lineSep
jjg@1230 473 + lineSep
jjg@1230 474 + "#ifndef _Included_" + cname + lineSep
jjg@1230 475 + "#define _Included_" + cname;
jjg@1230 476 }
jjg@1230 477
jjg@1230 478 protected String guardEnd(String cname) {
jjg@1230 479 return "#endif";
jjg@1230 480 }
jjg@1230 481
jjg@1230 482 protected void print(Writer out, String text) throws IOException {
jjg@1230 483 out.write(text);
jjg@1230 484 }
jjg@1230 485
jjg@1230 486 protected void println(Writer out, String text) throws IOException {
jjg@1230 487 out.write(text);
jjg@1230 488 out.write(lineSep);
jjg@1230 489 }
jjg@1230 490
jjg@1230 491
jjg@1230 492 private static class Mangle {
jjg@1230 493
jjg@1230 494 public static class Type {
jjg@1230 495 public static final int CLASS = 1;
jjg@1230 496 public static final int FIELDSTUB = 2;
jjg@1230 497 public static final int FIELD = 3;
jjg@1230 498 public static final int JNI = 4;
jjg@1230 499 public static final int SIGNATURE = 5;
jjg@1230 500 public static final int METHOD_JDK_1 = 6;
jjg@1230 501 public static final int METHOD_JNI_SHORT = 7;
jjg@1230 502 public static final int METHOD_JNI_LONG = 8;
jjg@1230 503 };
jjg@1230 504
jjg@1230 505 private Elements elems;
jjg@1230 506 private Types types;
jjg@1230 507
jjg@1230 508 Mangle(Elements elems, Types types) {
jjg@1230 509 this.elems = elems;
jjg@1230 510 this.types = types;
jjg@1230 511 }
jjg@1230 512
jjg@1230 513 public final String mangle(CharSequence name, int mtype) {
jjg@1230 514 StringBuilder result = new StringBuilder(100);
jjg@1230 515 int length = name.length();
jjg@1230 516
jjg@1230 517 for (int i = 0; i < length; i++) {
jjg@1230 518 char ch = name.charAt(i);
jjg@1230 519 if (isalnum(ch)) {
jjg@1230 520 result.append(ch);
jjg@1230 521 } else if ((ch == '.') &&
jjg@1230 522 mtype == Mangle.Type.CLASS) {
jjg@1230 523 result.append('_');
jjg@1230 524 } else if (( ch == '$') &&
jjg@1230 525 mtype == Mangle.Type.CLASS) {
jjg@1230 526 result.append('_');
jjg@1230 527 result.append('_');
jjg@1230 528 } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) {
jjg@1230 529 result.append('_');
jjg@1230 530 } else if (ch == '_' && mtype == Mangle.Type.CLASS) {
jjg@1230 531 result.append('_');
jjg@1230 532 } else if (mtype == Mangle.Type.JNI) {
jjg@1230 533 String esc = null;
jjg@1230 534 if (ch == '_')
jjg@1230 535 esc = "_1";
jjg@1230 536 else if (ch == '.')
jjg@1230 537 esc = "_";
jjg@1230 538 else if (ch == ';')
jjg@1230 539 esc = "_2";
jjg@1230 540 else if (ch == '[')
jjg@1230 541 esc = "_3";
jjg@1230 542 if (esc != null) {
jjg@1230 543 result.append(esc);
jjg@1230 544 } else {
jjg@1230 545 result.append(mangleChar(ch));
jjg@1230 546 }
jjg@1230 547 } else if (mtype == Mangle.Type.SIGNATURE) {
jjg@1230 548 if (isprint(ch)) {
jjg@1230 549 result.append(ch);
jjg@1230 550 } else {
jjg@1230 551 result.append(mangleChar(ch));
jjg@1230 552 }
jjg@1230 553 } else {
jjg@1230 554 result.append(mangleChar(ch));
jjg@1230 555 }
jjg@1230 556 }
jjg@1230 557
jjg@1230 558 return result.toString();
jjg@1230 559 }
jjg@1230 560
jjg@1230 561 public String mangleMethod(ExecutableElement method, TypeElement clazz,
jjg@1230 562 int mtype) throws TypeSignature.SignatureException {
jjg@1230 563 StringBuilder result = new StringBuilder(100);
jjg@1230 564 result.append("Java_");
jjg@1230 565
jjg@1230 566 if (mtype == Mangle.Type.METHOD_JDK_1) {
jjg@1230 567 result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS));
jjg@1230 568 result.append('_');
jjg@1230 569 result.append(mangle(method.getSimpleName(),
jjg@1230 570 Mangle.Type.FIELD));
jjg@1230 571 result.append("_stub");
jjg@1230 572 return result.toString();
jjg@1230 573 }
jjg@1230 574
jjg@1230 575 /* JNI */
jjg@1230 576 result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI));
jjg@1230 577 result.append('_');
jjg@1230 578 result.append(mangle(method.getSimpleName(),
jjg@1230 579 Mangle.Type.JNI));
jjg@1230 580 if (mtype == Mangle.Type.METHOD_JNI_LONG) {
jjg@1230 581 result.append("__");
jjg@1230 582 String typesig = signature(method);
jjg@1230 583 TypeSignature newTypeSig = new TypeSignature(elems);
jjg@1230 584 String sig = newTypeSig.getTypeSignature(typesig, method.getReturnType());
jjg@1230 585 sig = sig.substring(1);
jjg@1230 586 sig = sig.substring(0, sig.lastIndexOf(')'));
jjg@1230 587 sig = sig.replace('/', '.');
jjg@1230 588 result.append(mangle(sig, Mangle.Type.JNI));
jjg@1230 589 }
jjg@1230 590
jjg@1230 591 return result.toString();
jjg@1230 592 }
jjg@1230 593 //where
jjg@1230 594 private String getInnerQualifiedName(TypeElement clazz) {
jjg@1230 595 return elems.getBinaryName(clazz).toString();
jjg@1230 596 }
jjg@1230 597
jjg@1230 598 public final String mangleChar(char ch) {
jjg@1230 599 String s = Integer.toHexString(ch);
jjg@1230 600 int nzeros = 5 - s.length();
jjg@1230 601 char[] result = new char[6];
jjg@1230 602 result[0] = '_';
jjg@1230 603 for (int i = 1; i <= nzeros; i++)
jjg@1230 604 result[i] = '0';
jjg@1230 605 for (int i = nzeros+1, j = 0; i < 6; i++, j++)
jjg@1230 606 result[i] = s.charAt(j);
jjg@1230 607 return new String(result);
jjg@1230 608 }
jjg@1230 609
jjg@1230 610 // Warning: duplicated in Gen
jjg@1230 611 private String signature(ExecutableElement e) {
jjg@1230 612 StringBuilder sb = new StringBuilder();
jjg@1230 613 String sep = "(";
jjg@1230 614 for (VariableElement p: e.getParameters()) {
jjg@1230 615 sb.append(sep);
jjg@1230 616 sb.append(types.erasure(p.asType()).toString());
jjg@1230 617 sep = ",";
jjg@1230 618 }
jjg@1230 619 sb.append(")");
jjg@1230 620 return sb.toString();
jjg@1230 621 }
jjg@1230 622
jjg@1230 623 /* Warning: Intentional ASCII operation. */
jjg@1230 624 private static boolean isalnum(char ch) {
jjg@1230 625 return ch <= 0x7f && /* quick test */
jjg@1230 626 ((ch >= 'A' && ch <= 'Z') ||
jjg@1230 627 (ch >= 'a' && ch <= 'z') ||
jjg@1230 628 (ch >= '0' && ch <= '9'));
jjg@1230 629 }
jjg@1230 630
jjg@1230 631 /* Warning: Intentional ASCII operation. */
jjg@1230 632 private static boolean isprint(char ch) {
jjg@1230 633 return ch >= 32 && ch <= 126;
jjg@1230 634 }
jjg@1230 635 }
jjg@1230 636
jjg@1230 637 private static class TypeSignature {
jjg@1230 638 static class SignatureException extends Exception {
jjg@1230 639 private static final long serialVersionUID = 1L;
jjg@1230 640 SignatureException(String reason) {
jjg@1230 641 super(reason);
jjg@1230 642 }
jjg@1230 643 }
jjg@1230 644
jjg@1230 645 Elements elems;
jjg@1230 646
jjg@1230 647 /* Signature Characters */
jjg@1230 648
jjg@1230 649 private static final String SIG_VOID = "V";
jjg@1230 650 private static final String SIG_BOOLEAN = "Z";
jjg@1230 651 private static final String SIG_BYTE = "B";
jjg@1230 652 private static final String SIG_CHAR = "C";
jjg@1230 653 private static final String SIG_SHORT = "S";
jjg@1230 654 private static final String SIG_INT = "I";
jjg@1230 655 private static final String SIG_LONG = "J";
jjg@1230 656 private static final String SIG_FLOAT = "F";
jjg@1230 657 private static final String SIG_DOUBLE = "D";
jjg@1230 658 private static final String SIG_ARRAY = "[";
jjg@1230 659 private static final String SIG_CLASS = "L";
jjg@1230 660
jjg@1230 661
jjg@1230 662
jjg@1230 663 public TypeSignature(Elements elems){
jjg@1230 664 this.elems = elems;
jjg@1230 665 }
jjg@1230 666
jjg@1230 667 /*
jjg@1230 668 * Returns the type signature of a field according to JVM specs
jjg@1230 669 */
jjg@1230 670 public String getTypeSignature(String javasignature) throws SignatureException {
jjg@1230 671 return getParamJVMSignature(javasignature);
jjg@1230 672 }
jjg@1230 673
jjg@1230 674 /*
jjg@1230 675 * Returns the type signature of a method according to JVM specs
jjg@1230 676 */
jjg@1230 677 public String getTypeSignature(String javasignature, TypeMirror returnType)
jjg@1230 678 throws SignatureException {
jjg@1230 679 String signature = null; //Java type signature.
jjg@1230 680 String typeSignature = null; //Internal type signature.
jjg@1230 681 List<String> params = new ArrayList<String>(); //List of parameters.
jjg@1230 682 String paramsig = null; //Java parameter signature.
jjg@1230 683 String paramJVMSig = null; //Internal parameter signature.
jjg@1230 684 String returnSig = null; //Java return type signature.
jjg@1230 685 String returnJVMType = null; //Internal return type signature.
jjg@1230 686 int dimensions = 0; //Array dimension.
jjg@1230 687
jjg@1230 688 int startIndex = -1;
jjg@1230 689 int endIndex = -1;
jjg@1230 690 StringTokenizer st = null;
jjg@1230 691 int i = 0;
jjg@1230 692
jjg@1230 693 // Gets the actual java signature without parentheses.
jjg@1230 694 if (javasignature != null) {
jjg@1230 695 startIndex = javasignature.indexOf("(");
jjg@1230 696 endIndex = javasignature.indexOf(")");
jjg@1230 697 }
jjg@1230 698
jjg@1230 699 if (((startIndex != -1) && (endIndex != -1))
jjg@1230 700 &&(startIndex+1 < javasignature.length())
jjg@1230 701 &&(endIndex < javasignature.length())) {
jjg@1230 702 signature = javasignature.substring(startIndex+1, endIndex);
jjg@1230 703 }
jjg@1230 704
jjg@1230 705 // Separates parameters.
jjg@1230 706 if (signature != null) {
jjg@1230 707 if (signature.indexOf(",") != -1) {
jjg@1230 708 st = new StringTokenizer(signature, ",");
jjg@1230 709 if (st != null) {
jjg@1230 710 while (st.hasMoreTokens()) {
jjg@1230 711 params.add(st.nextToken());
jjg@1230 712 }
jjg@1230 713 }
jjg@1230 714 } else {
jjg@1230 715 params.add(signature);
jjg@1230 716 }
jjg@1230 717 }
jjg@1230 718
jjg@1230 719 /* JVM type signature. */
jjg@1230 720 typeSignature = "(";
jjg@1230 721
jjg@1230 722 // Gets indivisual internal parameter signature.
jjg@1230 723 while (params.isEmpty() != true) {
jjg@1230 724 paramsig = params.remove(i).trim();
jjg@1230 725 paramJVMSig = getParamJVMSignature(paramsig);
jjg@1230 726 if (paramJVMSig != null) {
jjg@1230 727 typeSignature += paramJVMSig;
jjg@1230 728 }
jjg@1230 729 }
jjg@1230 730
jjg@1230 731 typeSignature += ")";
jjg@1230 732
jjg@1230 733 // Get internal return type signature.
jjg@1230 734
jjg@1230 735 returnJVMType = "";
jjg@1230 736 if (returnType != null) {
jjg@1230 737 dimensions = dimensions(returnType);
jjg@1230 738 }
jjg@1230 739
jjg@1230 740 //Gets array dimension of return type.
jjg@1230 741 while (dimensions-- > 0) {
jjg@1230 742 returnJVMType += "[";
jjg@1230 743 }
jjg@1230 744 if (returnType != null) {
jjg@1230 745 returnSig = qualifiedTypeName(returnType);
jjg@1230 746 returnJVMType += getComponentType(returnSig);
jjg@1230 747 } else {
jjg@1230 748 System.out.println("Invalid return type.");
jjg@1230 749 }
jjg@1230 750
jjg@1230 751 typeSignature += returnJVMType;
jjg@1230 752
jjg@1230 753 return typeSignature;
jjg@1230 754 }
jjg@1230 755
jjg@1230 756 /*
jjg@1230 757 * Returns internal signature of a parameter.
jjg@1230 758 */
jjg@1230 759 private String getParamJVMSignature(String paramsig) throws SignatureException {
jjg@1230 760 String paramJVMSig = "";
jjg@1230 761 String componentType ="";
jjg@1230 762
jjg@1230 763 if(paramsig != null){
jjg@1230 764
jjg@1230 765 if(paramsig.indexOf("[]") != -1) {
jjg@1230 766 // Gets array dimension.
jjg@1230 767 int endindex = paramsig.indexOf("[]");
jjg@1230 768 componentType = paramsig.substring(0, endindex);
jjg@1230 769 String dimensionString = paramsig.substring(endindex);
jjg@1230 770 if(dimensionString != null){
jjg@1230 771 while(dimensionString.indexOf("[]") != -1){
jjg@1230 772 paramJVMSig += "[";
jjg@1230 773 int beginindex = dimensionString.indexOf("]") + 1;
jjg@1230 774 if(beginindex < dimensionString.length()){
jjg@1230 775 dimensionString = dimensionString.substring(beginindex);
jjg@1230 776 }else
jjg@1230 777 dimensionString = "";
jjg@1230 778 }
jjg@1230 779 }
jjg@1230 780 } else componentType = paramsig;
jjg@1230 781
jjg@1230 782 paramJVMSig += getComponentType(componentType);
jjg@1230 783 }
jjg@1230 784 return paramJVMSig;
jjg@1230 785 }
jjg@1230 786
jjg@1230 787 /*
jjg@1230 788 * Returns internal signature of a component.
jjg@1230 789 */
jjg@1230 790 private String getComponentType(String componentType) throws SignatureException {
jjg@1230 791
jjg@1230 792 String JVMSig = "";
jjg@1230 793
jjg@1230 794 if(componentType != null){
jjg@1230 795 if(componentType.equals("void")) JVMSig += SIG_VOID ;
jjg@1230 796 else if(componentType.equals("boolean")) JVMSig += SIG_BOOLEAN ;
jjg@1230 797 else if(componentType.equals("byte")) JVMSig += SIG_BYTE ;
jjg@1230 798 else if(componentType.equals("char")) JVMSig += SIG_CHAR ;
jjg@1230 799 else if(componentType.equals("short")) JVMSig += SIG_SHORT ;
jjg@1230 800 else if(componentType.equals("int")) JVMSig += SIG_INT ;
jjg@1230 801 else if(componentType.equals("long")) JVMSig += SIG_LONG ;
jjg@1230 802 else if(componentType.equals("float")) JVMSig += SIG_FLOAT ;
jjg@1230 803 else if(componentType.equals("double")) JVMSig += SIG_DOUBLE ;
jjg@1230 804 else {
jjg@1230 805 if(!componentType.equals("")){
jjg@1230 806 TypeElement classNameDoc = elems.getTypeElement(componentType);
jjg@1230 807
jjg@1230 808 if(classNameDoc == null){
jjg@1230 809 throw new SignatureException(componentType);
jjg@1230 810 }else {
jjg@1230 811 String classname = classNameDoc.getQualifiedName().toString();
jjg@1230 812 String newclassname = classname.replace('.', '/');
jjg@1230 813 JVMSig += "L";
jjg@1230 814 JVMSig += newclassname;
jjg@1230 815 JVMSig += ";";
jjg@1230 816 }
jjg@1230 817 }
jjg@1230 818 }
jjg@1230 819 }
jjg@1230 820 return JVMSig;
jjg@1230 821 }
jjg@1230 822
jjg@1230 823 int dimensions(TypeMirror t) {
jjg@1230 824 if (t.getKind() != TypeKind.ARRAY)
jjg@1230 825 return 0;
jjg@1230 826 return 1 + dimensions(((ArrayType) t).getComponentType());
jjg@1230 827 }
jjg@1230 828
jjg@1230 829
jjg@1230 830 String qualifiedTypeName(TypeMirror type) {
jjg@1230 831 TypeVisitor<Name, Void> v = new SimpleTypeVisitor8<Name, Void>() {
jjg@1230 832 @Override
jjg@1230 833 public Name visitArray(ArrayType t, Void p) {
jjg@1230 834 return t.getComponentType().accept(this, p);
jjg@1230 835 }
jjg@1230 836
jjg@1230 837 @Override
jjg@1230 838 public Name visitDeclared(DeclaredType t, Void p) {
jjg@1230 839 return ((TypeElement) t.asElement()).getQualifiedName();
jjg@1230 840 }
jjg@1230 841
jjg@1230 842 @Override
jjg@1230 843 public Name visitPrimitive(PrimitiveType t, Void p) {
jjg@1230 844 return elems.getName(t.toString());
jjg@1230 845 }
jjg@1230 846
jjg@1230 847 @Override
jjg@1230 848 public Name visitNoType(NoType t, Void p) {
jjg@1230 849 if (t.getKind() == TypeKind.VOID)
jjg@1230 850 return elems.getName("void");
jjg@1230 851 return defaultAction(t, p);
jjg@1230 852 }
jjg@1230 853
jjg@1230 854 @Override
jjg@1230 855 public Name visitTypeVariable(TypeVariable t, Void p) {
jjg@1230 856 return t.getUpperBound().accept(this, p);
jjg@1230 857 }
jjg@1230 858 };
jjg@1230 859 return v.visit(type).toString();
jjg@1230 860 }
jjg@1230 861 }
jjg@1230 862
jjg@1230 863 }

mercurial