1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java Tue Mar 13 15:43:40 2012 -0700 1.3 @@ -0,0 +1,856 @@ 1.4 +/* 1.5 + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.javac.jvm; 1.30 + 1.31 +import java.io.IOException; 1.32 +import java.io.Writer; 1.33 +import java.util.ArrayList; 1.34 +import java.util.List; 1.35 +import java.util.Stack; 1.36 +import java.util.StringTokenizer; 1.37 + 1.38 +import javax.lang.model.element.Element; 1.39 +import javax.lang.model.element.ExecutableElement; 1.40 +import javax.lang.model.element.Modifier; 1.41 +import javax.lang.model.element.Name; 1.42 +import javax.lang.model.element.TypeElement; 1.43 +import javax.lang.model.element.VariableElement; 1.44 +import javax.lang.model.type.ArrayType; 1.45 +import javax.lang.model.type.DeclaredType; 1.46 +import javax.lang.model.type.NoType; 1.47 +import javax.lang.model.type.PrimitiveType; 1.48 +import javax.lang.model.type.TypeKind; 1.49 +import javax.lang.model.type.TypeMirror; 1.50 +import javax.lang.model.type.TypeVariable; 1.51 +import javax.lang.model.type.TypeVisitor; 1.52 +import javax.lang.model.util.ElementFilter; 1.53 +import javax.lang.model.util.Elements; 1.54 +import javax.lang.model.util.SimpleTypeVisitor8; 1.55 +import javax.lang.model.util.Types; 1.56 + 1.57 +import javax.tools.FileObject; 1.58 +import javax.tools.JavaFileManager; 1.59 +import javax.tools.StandardLocation; 1.60 + 1.61 +import com.sun.tools.javac.code.Attribute; 1.62 +import com.sun.tools.javac.code.Flags; 1.63 +import com.sun.tools.javac.code.Kinds; 1.64 +import com.sun.tools.javac.code.Scope; 1.65 +import com.sun.tools.javac.code.Symbol.ClassSymbol; 1.66 +import com.sun.tools.javac.code.Symtab; 1.67 +import com.sun.tools.javac.model.JavacElements; 1.68 +import com.sun.tools.javac.model.JavacTypes; 1.69 +import com.sun.tools.javac.util.Assert; 1.70 +import com.sun.tools.javac.util.Context; 1.71 +import com.sun.tools.javac.util.Log; 1.72 +import com.sun.tools.javac.util.Options; 1.73 + 1.74 +import static com.sun.tools.javac.main.Option.*; 1.75 + 1.76 +/** This class provides operations to write native header files for classes. 1.77 + * 1.78 + * <p><b>This is NOT part of any supported API. 1.79 + * If you write code that depends on this, you do so at your own risk. 1.80 + * This code and its internal interfaces are subject to change or 1.81 + * deletion without notice.</b> 1.82 + */ 1.83 +public class JNIWriter { 1.84 + protected static final Context.Key<JNIWriter> jniWriterKey = 1.85 + new Context.Key<JNIWriter>(); 1.86 + 1.87 + /** Access to files. */ 1.88 + private final JavaFileManager fileManager; 1.89 + 1.90 + JavacElements elements; 1.91 + JavacTypes types; 1.92 + 1.93 + /** The log to use for verbose output. 1.94 + */ 1.95 + private final Log log; 1.96 + 1.97 + /** Switch: verbose output. 1.98 + */ 1.99 + private boolean verbose; 1.100 + 1.101 + /** Switch: check all nested classes of top level class 1.102 + */ 1.103 + private boolean checkAll; 1.104 + 1.105 + private Mangle mangler; 1.106 + 1.107 + private Context context; 1.108 + 1.109 + private Symtab syms; 1.110 + 1.111 + private String lineSep; 1.112 + 1.113 + private final boolean isWindows = 1.114 + System.getProperty("os.name").startsWith("Windows"); 1.115 + 1.116 + /** Get the ClassWriter instance for this context. */ 1.117 + public static JNIWriter instance(Context context) { 1.118 + JNIWriter instance = context.get(jniWriterKey); 1.119 + if (instance == null) 1.120 + instance = new JNIWriter(context); 1.121 + return instance; 1.122 + } 1.123 + 1.124 + /** Construct a class writer, given an options table. 1.125 + */ 1.126 + private JNIWriter(Context context) { 1.127 + context.put(jniWriterKey, this); 1.128 + fileManager = context.get(JavaFileManager.class); 1.129 + log = Log.instance(context); 1.130 + 1.131 + Options options = Options.instance(context); 1.132 + verbose = options.isSet(VERBOSE); 1.133 + checkAll = options.isSet("javah:full"); 1.134 + 1.135 + this.context = context; // for lazyInit() 1.136 + syms = Symtab.instance(context); 1.137 + 1.138 + lineSep = System.getProperty("line.separator"); 1.139 + } 1.140 + 1.141 + private void lazyInit() { 1.142 + if (mangler == null) { 1.143 + elements = JavacElements.instance(context); 1.144 + types = JavacTypes.instance(context); 1.145 + mangler = new Mangle(elements, types); 1.146 + } 1.147 + } 1.148 + 1.149 + public boolean needsHeader(ClassSymbol c) { 1.150 + if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) 1.151 + return false; 1.152 + 1.153 + if (checkAll) 1.154 + return needsHeader(c.outermostClass(), true); 1.155 + else 1.156 + return needsHeader(c, false); 1.157 + } 1.158 + 1.159 + private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) { 1.160 + if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) 1.161 + return false; 1.162 + 1.163 + for (Attribute.Compound a: c.attributes_field) { 1.164 + if (a.type.tsym == syms.nativeHeaderType.tsym) 1.165 + return true; 1.166 + } 1.167 + for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { 1.168 + if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0) 1.169 + return true; 1.170 + } 1.171 + if (checkNestedClasses) { 1.172 + for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { 1.173 + if ((i.sym.kind == Kinds.TYP) && needsHeader(((ClassSymbol) i.sym), true)) 1.174 + return true; 1.175 + } 1.176 + } 1.177 + return false; 1.178 + } 1.179 + 1.180 + /** Emit a class file for a given class. 1.181 + * @param c The class from which a class file is generated. 1.182 + */ 1.183 + public FileObject write(ClassSymbol c) 1.184 + throws IOException 1.185 + { 1.186 + String className = c.flatName().toString(); 1.187 + FileObject outFile 1.188 + = fileManager.getFileForOutput(StandardLocation.NATIVE_HEADER_OUTPUT, 1.189 + "", className.replaceAll("[.$]", "_") + ".h", null); 1.190 + Writer out = outFile.openWriter(); 1.191 + try { 1.192 + write(out, c); 1.193 + if (verbose) 1.194 + log.printVerbose("wrote.file", outFile); 1.195 + out.close(); 1.196 + out = null; 1.197 + } finally { 1.198 + if (out != null) { 1.199 + // if we are propogating an exception, delete the file 1.200 + out.close(); 1.201 + outFile.delete(); 1.202 + outFile = null; 1.203 + } 1.204 + } 1.205 + return outFile; // may be null if write failed 1.206 + } 1.207 + 1.208 + public void write(Writer out, ClassSymbol sym) 1.209 + throws IOException { 1.210 + lazyInit(); 1.211 + try { 1.212 + String cname = mangler.mangle(sym.fullname, Mangle.Type.CLASS); 1.213 + println(out, fileTop()); 1.214 + println(out, includes()); 1.215 + println(out, guardBegin(cname)); 1.216 + println(out, cppGuardBegin()); 1.217 + 1.218 + writeStatics(out, sym); 1.219 + writeMethods(out, sym, cname); 1.220 + 1.221 + println(out, cppGuardEnd()); 1.222 + println(out, guardEnd(cname)); 1.223 + } catch (TypeSignature.SignatureException e) { 1.224 + throw new IOException(e); 1.225 + } 1.226 + } 1.227 + 1.228 + protected void writeStatics(Writer out, ClassSymbol sym) throws IOException { 1.229 + List<VariableElement> classfields = getAllFields(sym); 1.230 + 1.231 + for (VariableElement v: classfields) { 1.232 + if (!v.getModifiers().contains(Modifier.STATIC)) 1.233 + continue; 1.234 + String s = null; 1.235 + s = defineForStatic(sym, v); 1.236 + if (s != null) { 1.237 + println(out, s); 1.238 + } 1.239 + } 1.240 + } 1.241 + 1.242 + /** 1.243 + * Including super class fields. 1.244 + */ 1.245 + List<VariableElement> getAllFields(TypeElement subclazz) { 1.246 + List<VariableElement> fields = new ArrayList<VariableElement>(); 1.247 + TypeElement cd = null; 1.248 + Stack<TypeElement> s = new Stack<TypeElement>(); 1.249 + 1.250 + cd = subclazz; 1.251 + while (true) { 1.252 + s.push(cd); 1.253 + TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass())); 1.254 + if (c == null) 1.255 + break; 1.256 + cd = c; 1.257 + } 1.258 + 1.259 + while (!s.empty()) { 1.260 + cd = s.pop(); 1.261 + fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements())); 1.262 + } 1.263 + 1.264 + return fields; 1.265 + } 1.266 + 1.267 + protected String defineForStatic(TypeElement c, VariableElement f) { 1.268 + CharSequence cnamedoc = c.getQualifiedName(); 1.269 + CharSequence fnamedoc = f.getSimpleName(); 1.270 + 1.271 + String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS); 1.272 + String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB); 1.273 + 1.274 + Assert.check(f.getModifiers().contains(Modifier.STATIC)); 1.275 + 1.276 + if (f.getModifiers().contains(Modifier.FINAL)) { 1.277 + Object value = null; 1.278 + 1.279 + value = f.getConstantValue(); 1.280 + 1.281 + if (value != null) { /* so it is a ConstantExpression */ 1.282 + String constString = null; 1.283 + if ((value instanceof Integer) 1.284 + || (value instanceof Byte) 1.285 + || (value instanceof Short)) { 1.286 + /* covers byte, short, int */ 1.287 + constString = value.toString() + "L"; 1.288 + } else if (value instanceof Boolean) { 1.289 + constString = ((Boolean) value) ? "1L" : "0L"; 1.290 + } else if (value instanceof Character) { 1.291 + Character ch = (Character) value; 1.292 + constString = String.valueOf(((int) ch) & 0xffff) + "L"; 1.293 + } else if (value instanceof Long) { 1.294 + // Visual C++ supports the i64 suffix, not LL. 1.295 + if (isWindows) 1.296 + constString = value.toString() + "i64"; 1.297 + else 1.298 + constString = value.toString() + "LL"; 1.299 + } else if (value instanceof Float) { 1.300 + /* bug for bug */ 1.301 + float fv = ((Float)value).floatValue(); 1.302 + if (Float.isInfinite(fv)) 1.303 + constString = ((fv < 0) ? "-" : "") + "Inff"; 1.304 + else 1.305 + constString = value.toString() + "f"; 1.306 + } else if (value instanceof Double) { 1.307 + /* bug for bug */ 1.308 + double d = ((Double)value).doubleValue(); 1.309 + if (Double.isInfinite(d)) 1.310 + constString = ((d < 0) ? "-" : "") + "InfD"; 1.311 + else 1.312 + constString = value.toString(); 1.313 + } 1.314 + 1.315 + if (constString != null) { 1.316 + StringBuilder s = new StringBuilder("#undef "); 1.317 + s.append(cname); s.append("_"); s.append(fname); s.append(lineSep); 1.318 + s.append("#define "); s.append(cname); s.append("_"); 1.319 + s.append(fname); s.append(" "); s.append(constString); 1.320 + return s.toString(); 1.321 + } 1.322 + 1.323 + } 1.324 + } 1.325 + 1.326 + return null; 1.327 + } 1.328 + 1.329 + 1.330 + protected void writeMethods(Writer out, ClassSymbol sym, String cname) 1.331 + throws IOException, TypeSignature.SignatureException { 1.332 + List<ExecutableElement> classmethods = ElementFilter.methodsIn(sym.getEnclosedElements()); 1.333 + for (ExecutableElement md: classmethods) { 1.334 + if(md.getModifiers().contains(Modifier.NATIVE)){ 1.335 + TypeMirror mtr = types.erasure(md.getReturnType()); 1.336 + String sig = signature(md); 1.337 + TypeSignature newtypesig = new TypeSignature(elements); 1.338 + CharSequence methodName = md.getSimpleName(); 1.339 + boolean longName = false; 1.340 + for (ExecutableElement md2: classmethods) { 1.341 + if ((md2 != md) 1.342 + && (methodName.equals(md2.getSimpleName())) 1.343 + && (md2.getModifiers().contains(Modifier.NATIVE))) 1.344 + longName = true; 1.345 + 1.346 + } 1.347 + println(out, "/*"); 1.348 + println(out, " * Class: " + cname); 1.349 + println(out, " * Method: " + 1.350 + mangler.mangle(methodName, Mangle.Type.FIELDSTUB)); 1.351 + println(out, " * Signature: " + newtypesig.getTypeSignature(sig, mtr)); 1.352 + println(out, " */"); 1.353 + println(out, "JNIEXPORT " + jniType(mtr) + 1.354 + " JNICALL " + 1.355 + mangler.mangleMethod(md, sym, 1.356 + (longName) ? 1.357 + Mangle.Type.METHOD_JNI_LONG : 1.358 + Mangle.Type.METHOD_JNI_SHORT)); 1.359 + print(out, " (JNIEnv *, "); 1.360 + List<? extends VariableElement> paramargs = md.getParameters(); 1.361 + List<TypeMirror> args = new ArrayList<TypeMirror>(); 1.362 + for (VariableElement p: paramargs) { 1.363 + args.add(types.erasure(p.asType())); 1.364 + } 1.365 + if (md.getModifiers().contains(Modifier.STATIC)) 1.366 + print(out, "jclass"); 1.367 + else 1.368 + print(out, "jobject"); 1.369 + 1.370 + for (TypeMirror arg: args) { 1.371 + print(out, ", "); 1.372 + print(out, jniType(arg)); 1.373 + } 1.374 + println(out, ");" 1.375 + + lineSep); 1.376 + } 1.377 + } 1.378 + } 1.379 + 1.380 + // c.f. MethodDoc.signature 1.381 + String signature(ExecutableElement e) { 1.382 + StringBuilder sb = new StringBuilder("("); 1.383 + String sep = ""; 1.384 + for (VariableElement p: e.getParameters()) { 1.385 + sb.append(sep); 1.386 + sb.append(types.erasure(p.asType()).toString()); 1.387 + sep = ","; 1.388 + } 1.389 + sb.append(")"); 1.390 + return sb.toString(); 1.391 + } 1.392 + 1.393 + protected final String jniType(TypeMirror t) { 1.394 + TypeElement throwable = elements.getTypeElement("java.lang.Throwable"); 1.395 + TypeElement jClass = elements.getTypeElement("java.lang.Class"); 1.396 + TypeElement jString = elements.getTypeElement("java.lang.String"); 1.397 + Element tclassDoc = types.asElement(t); 1.398 + 1.399 + 1.400 + switch (t.getKind()) { 1.401 + case ARRAY: { 1.402 + TypeMirror ct = ((ArrayType) t).getComponentType(); 1.403 + switch (ct.getKind()) { 1.404 + case BOOLEAN: return "jbooleanArray"; 1.405 + case BYTE: return "jbyteArray"; 1.406 + case CHAR: return "jcharArray"; 1.407 + case SHORT: return "jshortArray"; 1.408 + case INT: return "jintArray"; 1.409 + case LONG: return "jlongArray"; 1.410 + case FLOAT: return "jfloatArray"; 1.411 + case DOUBLE: return "jdoubleArray"; 1.412 + case ARRAY: 1.413 + case DECLARED: return "jobjectArray"; 1.414 + default: throw new Error(ct.toString()); 1.415 + } 1.416 + } 1.417 + 1.418 + case VOID: return "void"; 1.419 + case BOOLEAN: return "jboolean"; 1.420 + case BYTE: return "jbyte"; 1.421 + case CHAR: return "jchar"; 1.422 + case SHORT: return "jshort"; 1.423 + case INT: return "jint"; 1.424 + case LONG: return "jlong"; 1.425 + case FLOAT: return "jfloat"; 1.426 + case DOUBLE: return "jdouble"; 1.427 + 1.428 + case DECLARED: { 1.429 + if (tclassDoc.equals(jString)) 1.430 + return "jstring"; 1.431 + else if (types.isAssignable(t, throwable.asType())) 1.432 + return "jthrowable"; 1.433 + else if (types.isAssignable(t, jClass.asType())) 1.434 + return "jclass"; 1.435 + else 1.436 + return "jobject"; 1.437 + } 1.438 + } 1.439 + 1.440 + Assert.check(false, "jni unknown type"); 1.441 + return null; /* dead code. */ 1.442 + } 1.443 + 1.444 + protected String fileTop() { 1.445 + return "/* DO NOT EDIT THIS FILE - it is machine generated */"; 1.446 + } 1.447 + 1.448 + protected String includes() { 1.449 + return "#include <jni.h>"; 1.450 + } 1.451 + 1.452 + /* 1.453 + * Deal with the C pre-processor. 1.454 + */ 1.455 + protected String cppGuardBegin() { 1.456 + return "#ifdef __cplusplus" + lineSep 1.457 + + "extern \"C\" {" + lineSep 1.458 + + "#endif"; 1.459 + } 1.460 + 1.461 + protected String cppGuardEnd() { 1.462 + return "#ifdef __cplusplus" + lineSep 1.463 + + "}" + lineSep 1.464 + + "#endif"; 1.465 + } 1.466 + 1.467 + protected String guardBegin(String cname) { 1.468 + return "/* Header for class " + cname + " */" + lineSep 1.469 + + lineSep 1.470 + + "#ifndef _Included_" + cname + lineSep 1.471 + + "#define _Included_" + cname; 1.472 + } 1.473 + 1.474 + protected String guardEnd(String cname) { 1.475 + return "#endif"; 1.476 + } 1.477 + 1.478 + protected void print(Writer out, String text) throws IOException { 1.479 + out.write(text); 1.480 + } 1.481 + 1.482 + protected void println(Writer out, String text) throws IOException { 1.483 + out.write(text); 1.484 + out.write(lineSep); 1.485 + } 1.486 + 1.487 + 1.488 + private static class Mangle { 1.489 + 1.490 + public static class Type { 1.491 + public static final int CLASS = 1; 1.492 + public static final int FIELDSTUB = 2; 1.493 + public static final int FIELD = 3; 1.494 + public static final int JNI = 4; 1.495 + public static final int SIGNATURE = 5; 1.496 + public static final int METHOD_JDK_1 = 6; 1.497 + public static final int METHOD_JNI_SHORT = 7; 1.498 + public static final int METHOD_JNI_LONG = 8; 1.499 + }; 1.500 + 1.501 + private Elements elems; 1.502 + private Types types; 1.503 + 1.504 + Mangle(Elements elems, Types types) { 1.505 + this.elems = elems; 1.506 + this.types = types; 1.507 + } 1.508 + 1.509 + public final String mangle(CharSequence name, int mtype) { 1.510 + StringBuilder result = new StringBuilder(100); 1.511 + int length = name.length(); 1.512 + 1.513 + for (int i = 0; i < length; i++) { 1.514 + char ch = name.charAt(i); 1.515 + if (isalnum(ch)) { 1.516 + result.append(ch); 1.517 + } else if ((ch == '.') && 1.518 + mtype == Mangle.Type.CLASS) { 1.519 + result.append('_'); 1.520 + } else if (( ch == '$') && 1.521 + mtype == Mangle.Type.CLASS) { 1.522 + result.append('_'); 1.523 + result.append('_'); 1.524 + } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) { 1.525 + result.append('_'); 1.526 + } else if (ch == '_' && mtype == Mangle.Type.CLASS) { 1.527 + result.append('_'); 1.528 + } else if (mtype == Mangle.Type.JNI) { 1.529 + String esc = null; 1.530 + if (ch == '_') 1.531 + esc = "_1"; 1.532 + else if (ch == '.') 1.533 + esc = "_"; 1.534 + else if (ch == ';') 1.535 + esc = "_2"; 1.536 + else if (ch == '[') 1.537 + esc = "_3"; 1.538 + if (esc != null) { 1.539 + result.append(esc); 1.540 + } else { 1.541 + result.append(mangleChar(ch)); 1.542 + } 1.543 + } else if (mtype == Mangle.Type.SIGNATURE) { 1.544 + if (isprint(ch)) { 1.545 + result.append(ch); 1.546 + } else { 1.547 + result.append(mangleChar(ch)); 1.548 + } 1.549 + } else { 1.550 + result.append(mangleChar(ch)); 1.551 + } 1.552 + } 1.553 + 1.554 + return result.toString(); 1.555 + } 1.556 + 1.557 + public String mangleMethod(ExecutableElement method, TypeElement clazz, 1.558 + int mtype) throws TypeSignature.SignatureException { 1.559 + StringBuilder result = new StringBuilder(100); 1.560 + result.append("Java_"); 1.561 + 1.562 + if (mtype == Mangle.Type.METHOD_JDK_1) { 1.563 + result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS)); 1.564 + result.append('_'); 1.565 + result.append(mangle(method.getSimpleName(), 1.566 + Mangle.Type.FIELD)); 1.567 + result.append("_stub"); 1.568 + return result.toString(); 1.569 + } 1.570 + 1.571 + /* JNI */ 1.572 + result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI)); 1.573 + result.append('_'); 1.574 + result.append(mangle(method.getSimpleName(), 1.575 + Mangle.Type.JNI)); 1.576 + if (mtype == Mangle.Type.METHOD_JNI_LONG) { 1.577 + result.append("__"); 1.578 + String typesig = signature(method); 1.579 + TypeSignature newTypeSig = new TypeSignature(elems); 1.580 + String sig = newTypeSig.getTypeSignature(typesig, method.getReturnType()); 1.581 + sig = sig.substring(1); 1.582 + sig = sig.substring(0, sig.lastIndexOf(')')); 1.583 + sig = sig.replace('/', '.'); 1.584 + result.append(mangle(sig, Mangle.Type.JNI)); 1.585 + } 1.586 + 1.587 + return result.toString(); 1.588 + } 1.589 + //where 1.590 + private String getInnerQualifiedName(TypeElement clazz) { 1.591 + return elems.getBinaryName(clazz).toString(); 1.592 + } 1.593 + 1.594 + public final String mangleChar(char ch) { 1.595 + String s = Integer.toHexString(ch); 1.596 + int nzeros = 5 - s.length(); 1.597 + char[] result = new char[6]; 1.598 + result[0] = '_'; 1.599 + for (int i = 1; i <= nzeros; i++) 1.600 + result[i] = '0'; 1.601 + for (int i = nzeros+1, j = 0; i < 6; i++, j++) 1.602 + result[i] = s.charAt(j); 1.603 + return new String(result); 1.604 + } 1.605 + 1.606 + // Warning: duplicated in Gen 1.607 + private String signature(ExecutableElement e) { 1.608 + StringBuilder sb = new StringBuilder(); 1.609 + String sep = "("; 1.610 + for (VariableElement p: e.getParameters()) { 1.611 + sb.append(sep); 1.612 + sb.append(types.erasure(p.asType()).toString()); 1.613 + sep = ","; 1.614 + } 1.615 + sb.append(")"); 1.616 + return sb.toString(); 1.617 + } 1.618 + 1.619 + /* Warning: Intentional ASCII operation. */ 1.620 + private static boolean isalnum(char ch) { 1.621 + return ch <= 0x7f && /* quick test */ 1.622 + ((ch >= 'A' && ch <= 'Z') || 1.623 + (ch >= 'a' && ch <= 'z') || 1.624 + (ch >= '0' && ch <= '9')); 1.625 + } 1.626 + 1.627 + /* Warning: Intentional ASCII operation. */ 1.628 + private static boolean isprint(char ch) { 1.629 + return ch >= 32 && ch <= 126; 1.630 + } 1.631 + } 1.632 + 1.633 + private static class TypeSignature { 1.634 + static class SignatureException extends Exception { 1.635 + private static final long serialVersionUID = 1L; 1.636 + SignatureException(String reason) { 1.637 + super(reason); 1.638 + } 1.639 + } 1.640 + 1.641 + Elements elems; 1.642 + 1.643 + /* Signature Characters */ 1.644 + 1.645 + private static final String SIG_VOID = "V"; 1.646 + private static final String SIG_BOOLEAN = "Z"; 1.647 + private static final String SIG_BYTE = "B"; 1.648 + private static final String SIG_CHAR = "C"; 1.649 + private static final String SIG_SHORT = "S"; 1.650 + private static final String SIG_INT = "I"; 1.651 + private static final String SIG_LONG = "J"; 1.652 + private static final String SIG_FLOAT = "F"; 1.653 + private static final String SIG_DOUBLE = "D"; 1.654 + private static final String SIG_ARRAY = "["; 1.655 + private static final String SIG_CLASS = "L"; 1.656 + 1.657 + 1.658 + 1.659 + public TypeSignature(Elements elems){ 1.660 + this.elems = elems; 1.661 + } 1.662 + 1.663 + /* 1.664 + * Returns the type signature of a field according to JVM specs 1.665 + */ 1.666 + public String getTypeSignature(String javasignature) throws SignatureException { 1.667 + return getParamJVMSignature(javasignature); 1.668 + } 1.669 + 1.670 + /* 1.671 + * Returns the type signature of a method according to JVM specs 1.672 + */ 1.673 + public String getTypeSignature(String javasignature, TypeMirror returnType) 1.674 + throws SignatureException { 1.675 + String signature = null; //Java type signature. 1.676 + String typeSignature = null; //Internal type signature. 1.677 + List<String> params = new ArrayList<String>(); //List of parameters. 1.678 + String paramsig = null; //Java parameter signature. 1.679 + String paramJVMSig = null; //Internal parameter signature. 1.680 + String returnSig = null; //Java return type signature. 1.681 + String returnJVMType = null; //Internal return type signature. 1.682 + int dimensions = 0; //Array dimension. 1.683 + 1.684 + int startIndex = -1; 1.685 + int endIndex = -1; 1.686 + StringTokenizer st = null; 1.687 + int i = 0; 1.688 + 1.689 + // Gets the actual java signature without parentheses. 1.690 + if (javasignature != null) { 1.691 + startIndex = javasignature.indexOf("("); 1.692 + endIndex = javasignature.indexOf(")"); 1.693 + } 1.694 + 1.695 + if (((startIndex != -1) && (endIndex != -1)) 1.696 + &&(startIndex+1 < javasignature.length()) 1.697 + &&(endIndex < javasignature.length())) { 1.698 + signature = javasignature.substring(startIndex+1, endIndex); 1.699 + } 1.700 + 1.701 + // Separates parameters. 1.702 + if (signature != null) { 1.703 + if (signature.indexOf(",") != -1) { 1.704 + st = new StringTokenizer(signature, ","); 1.705 + if (st != null) { 1.706 + while (st.hasMoreTokens()) { 1.707 + params.add(st.nextToken()); 1.708 + } 1.709 + } 1.710 + } else { 1.711 + params.add(signature); 1.712 + } 1.713 + } 1.714 + 1.715 + /* JVM type signature. */ 1.716 + typeSignature = "("; 1.717 + 1.718 + // Gets indivisual internal parameter signature. 1.719 + while (params.isEmpty() != true) { 1.720 + paramsig = params.remove(i).trim(); 1.721 + paramJVMSig = getParamJVMSignature(paramsig); 1.722 + if (paramJVMSig != null) { 1.723 + typeSignature += paramJVMSig; 1.724 + } 1.725 + } 1.726 + 1.727 + typeSignature += ")"; 1.728 + 1.729 + // Get internal return type signature. 1.730 + 1.731 + returnJVMType = ""; 1.732 + if (returnType != null) { 1.733 + dimensions = dimensions(returnType); 1.734 + } 1.735 + 1.736 + //Gets array dimension of return type. 1.737 + while (dimensions-- > 0) { 1.738 + returnJVMType += "["; 1.739 + } 1.740 + if (returnType != null) { 1.741 + returnSig = qualifiedTypeName(returnType); 1.742 + returnJVMType += getComponentType(returnSig); 1.743 + } else { 1.744 + System.out.println("Invalid return type."); 1.745 + } 1.746 + 1.747 + typeSignature += returnJVMType; 1.748 + 1.749 + return typeSignature; 1.750 + } 1.751 + 1.752 + /* 1.753 + * Returns internal signature of a parameter. 1.754 + */ 1.755 + private String getParamJVMSignature(String paramsig) throws SignatureException { 1.756 + String paramJVMSig = ""; 1.757 + String componentType =""; 1.758 + 1.759 + if(paramsig != null){ 1.760 + 1.761 + if(paramsig.indexOf("[]") != -1) { 1.762 + // Gets array dimension. 1.763 + int endindex = paramsig.indexOf("[]"); 1.764 + componentType = paramsig.substring(0, endindex); 1.765 + String dimensionString = paramsig.substring(endindex); 1.766 + if(dimensionString != null){ 1.767 + while(dimensionString.indexOf("[]") != -1){ 1.768 + paramJVMSig += "["; 1.769 + int beginindex = dimensionString.indexOf("]") + 1; 1.770 + if(beginindex < dimensionString.length()){ 1.771 + dimensionString = dimensionString.substring(beginindex); 1.772 + }else 1.773 + dimensionString = ""; 1.774 + } 1.775 + } 1.776 + } else componentType = paramsig; 1.777 + 1.778 + paramJVMSig += getComponentType(componentType); 1.779 + } 1.780 + return paramJVMSig; 1.781 + } 1.782 + 1.783 + /* 1.784 + * Returns internal signature of a component. 1.785 + */ 1.786 + private String getComponentType(String componentType) throws SignatureException { 1.787 + 1.788 + String JVMSig = ""; 1.789 + 1.790 + if(componentType != null){ 1.791 + if(componentType.equals("void")) JVMSig += SIG_VOID ; 1.792 + else if(componentType.equals("boolean")) JVMSig += SIG_BOOLEAN ; 1.793 + else if(componentType.equals("byte")) JVMSig += SIG_BYTE ; 1.794 + else if(componentType.equals("char")) JVMSig += SIG_CHAR ; 1.795 + else if(componentType.equals("short")) JVMSig += SIG_SHORT ; 1.796 + else if(componentType.equals("int")) JVMSig += SIG_INT ; 1.797 + else if(componentType.equals("long")) JVMSig += SIG_LONG ; 1.798 + else if(componentType.equals("float")) JVMSig += SIG_FLOAT ; 1.799 + else if(componentType.equals("double")) JVMSig += SIG_DOUBLE ; 1.800 + else { 1.801 + if(!componentType.equals("")){ 1.802 + TypeElement classNameDoc = elems.getTypeElement(componentType); 1.803 + 1.804 + if(classNameDoc == null){ 1.805 + throw new SignatureException(componentType); 1.806 + }else { 1.807 + String classname = classNameDoc.getQualifiedName().toString(); 1.808 + String newclassname = classname.replace('.', '/'); 1.809 + JVMSig += "L"; 1.810 + JVMSig += newclassname; 1.811 + JVMSig += ";"; 1.812 + } 1.813 + } 1.814 + } 1.815 + } 1.816 + return JVMSig; 1.817 + } 1.818 + 1.819 + int dimensions(TypeMirror t) { 1.820 + if (t.getKind() != TypeKind.ARRAY) 1.821 + return 0; 1.822 + return 1 + dimensions(((ArrayType) t).getComponentType()); 1.823 + } 1.824 + 1.825 + 1.826 + String qualifiedTypeName(TypeMirror type) { 1.827 + TypeVisitor<Name, Void> v = new SimpleTypeVisitor8<Name, Void>() { 1.828 + @Override 1.829 + public Name visitArray(ArrayType t, Void p) { 1.830 + return t.getComponentType().accept(this, p); 1.831 + } 1.832 + 1.833 + @Override 1.834 + public Name visitDeclared(DeclaredType t, Void p) { 1.835 + return ((TypeElement) t.asElement()).getQualifiedName(); 1.836 + } 1.837 + 1.838 + @Override 1.839 + public Name visitPrimitive(PrimitiveType t, Void p) { 1.840 + return elems.getName(t.toString()); 1.841 + } 1.842 + 1.843 + @Override 1.844 + public Name visitNoType(NoType t, Void p) { 1.845 + if (t.getKind() == TypeKind.VOID) 1.846 + return elems.getName("void"); 1.847 + return defaultAction(t, p); 1.848 + } 1.849 + 1.850 + @Override 1.851 + public Name visitTypeVariable(TypeVariable t, Void p) { 1.852 + return t.getUpperBound().accept(this, p); 1.853 + } 1.854 + }; 1.855 + return v.visit(type).toString(); 1.856 + } 1.857 + } 1.858 + 1.859 +}