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

Thu, 12 Oct 2017 19:50:01 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:50:01 +0800
changeset 2702
9ca8d8713094
parent 2525
2eb010b6cb22
permissions
-rw-r--r--

merge

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

mercurial