aoqi@0: /* aoqi@0: * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.javac.jvm; aoqi@0: aoqi@0: import java.io.IOException; aoqi@0: import java.io.Writer; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.List; aoqi@0: import java.util.Stack; aoqi@0: import java.util.StringTokenizer; aoqi@0: aoqi@0: import javax.lang.model.element.Element; aoqi@0: import javax.lang.model.element.ExecutableElement; aoqi@0: import javax.lang.model.element.Modifier; aoqi@0: import javax.lang.model.element.Name; aoqi@0: import javax.lang.model.element.TypeElement; aoqi@0: import javax.lang.model.element.VariableElement; aoqi@0: import javax.lang.model.type.ArrayType; aoqi@0: import javax.lang.model.type.DeclaredType; aoqi@0: import javax.lang.model.type.NoType; aoqi@0: import javax.lang.model.type.PrimitiveType; aoqi@0: import javax.lang.model.type.TypeKind; aoqi@0: import javax.lang.model.type.TypeMirror; aoqi@0: import javax.lang.model.type.TypeVariable; aoqi@0: import javax.lang.model.type.TypeVisitor; aoqi@0: import javax.lang.model.util.ElementFilter; aoqi@0: import javax.lang.model.util.Elements; aoqi@0: import javax.lang.model.util.SimpleTypeVisitor8; aoqi@0: import javax.lang.model.util.Types; aoqi@0: aoqi@0: import javax.tools.FileObject; aoqi@0: import javax.tools.JavaFileManager; aoqi@0: import javax.tools.StandardLocation; aoqi@0: aoqi@0: import com.sun.tools.javac.code.Attribute; aoqi@0: import com.sun.tools.javac.code.Flags; aoqi@0: import com.sun.tools.javac.code.Kinds; aoqi@0: import com.sun.tools.javac.code.Scope; aoqi@0: import com.sun.tools.javac.code.Symbol.ClassSymbol; aoqi@0: import com.sun.tools.javac.code.Symtab; aoqi@0: import com.sun.tools.javac.model.JavacElements; aoqi@0: import com.sun.tools.javac.model.JavacTypes; aoqi@0: import com.sun.tools.javac.util.Assert; aoqi@0: import com.sun.tools.javac.util.Context; aoqi@0: import com.sun.tools.javac.util.Log; aoqi@0: import com.sun.tools.javac.util.Options; aoqi@0: aoqi@0: import static com.sun.tools.javac.main.Option.*; aoqi@0: aoqi@0: /** This class provides operations to write native header files for classes. aoqi@0: * aoqi@0: *

This is NOT part of any supported API. aoqi@0: * If you write code that depends on this, you do so at your own risk. aoqi@0: * This code and its internal interfaces are subject to change or aoqi@0: * deletion without notice. aoqi@0: */ aoqi@0: public class JNIWriter { aoqi@0: protected static final Context.Key jniWriterKey = aoqi@0: new Context.Key(); aoqi@0: aoqi@0: /** Access to files. */ aoqi@0: private final JavaFileManager fileManager; aoqi@0: aoqi@0: JavacElements elements; aoqi@0: JavacTypes types; aoqi@0: aoqi@0: /** The log to use for verbose output. aoqi@0: */ aoqi@0: private final Log log; aoqi@0: aoqi@0: /** Switch: verbose output. aoqi@0: */ aoqi@0: private boolean verbose; aoqi@0: aoqi@0: /** Switch: check all nested classes of top level class aoqi@0: */ aoqi@0: private boolean checkAll; aoqi@0: aoqi@0: private Mangle mangler; aoqi@0: aoqi@0: private Context context; aoqi@0: aoqi@0: private Symtab syms; aoqi@0: aoqi@0: private String lineSep; aoqi@0: aoqi@0: private final boolean isWindows = aoqi@0: System.getProperty("os.name").startsWith("Windows"); aoqi@0: aoqi@0: /** Get the ClassWriter instance for this context. */ aoqi@0: public static JNIWriter instance(Context context) { aoqi@0: JNIWriter instance = context.get(jniWriterKey); aoqi@0: if (instance == null) aoqi@0: instance = new JNIWriter(context); aoqi@0: return instance; aoqi@0: } aoqi@0: aoqi@0: /** Construct a class writer, given an options table. aoqi@0: */ aoqi@0: private JNIWriter(Context context) { aoqi@0: context.put(jniWriterKey, this); aoqi@0: fileManager = context.get(JavaFileManager.class); aoqi@0: log = Log.instance(context); aoqi@0: aoqi@0: Options options = Options.instance(context); aoqi@0: verbose = options.isSet(VERBOSE); aoqi@0: checkAll = options.isSet("javah:full"); aoqi@0: aoqi@0: this.context = context; // for lazyInit() aoqi@0: syms = Symtab.instance(context); aoqi@0: aoqi@0: lineSep = System.getProperty("line.separator"); aoqi@0: } aoqi@0: aoqi@0: private void lazyInit() { aoqi@0: if (mangler == null) { aoqi@0: elements = JavacElements.instance(context); aoqi@0: types = JavacTypes.instance(context); aoqi@0: mangler = new Mangle(elements, types); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public boolean needsHeader(ClassSymbol c) { aoqi@0: if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) aoqi@0: return false; aoqi@0: aoqi@0: if (checkAll) aoqi@0: return needsHeader(c.outermostClass(), true); aoqi@0: else aoqi@0: return needsHeader(c, false); aoqi@0: } aoqi@0: aoqi@0: private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) { aoqi@0: if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) aoqi@0: return false; aoqi@0: aoqi@0: for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { aoqi@0: if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0) aoqi@0: return true; aoqi@0: for (Attribute.Compound a: i.sym.getDeclarationAttributes()) { aoqi@0: if (a.type.tsym == syms.nativeHeaderType.tsym) aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: if (checkNestedClasses) { aoqi@0: for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { aoqi@0: if ((i.sym.kind == Kinds.TYP) && needsHeader(((ClassSymbol) i.sym), true)) aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: /** Emit a class file for a given class. aoqi@0: * @param c The class from which a class file is generated. aoqi@0: */ aoqi@0: public FileObject write(ClassSymbol c) aoqi@0: throws IOException aoqi@0: { aoqi@0: String className = c.flatName().toString(); aoqi@0: FileObject outFile aoqi@0: = fileManager.getFileForOutput(StandardLocation.NATIVE_HEADER_OUTPUT, aoqi@0: "", className.replaceAll("[.$]", "_") + ".h", null); aoqi@0: Writer out = outFile.openWriter(); aoqi@0: try { aoqi@0: write(out, c); aoqi@0: if (verbose) aoqi@0: log.printVerbose("wrote.file", outFile); aoqi@0: out.close(); aoqi@0: out = null; aoqi@0: } finally { aoqi@0: if (out != null) { aoqi@0: // if we are propogating an exception, delete the file aoqi@0: out.close(); aoqi@0: outFile.delete(); aoqi@0: outFile = null; aoqi@0: } aoqi@0: } aoqi@0: return outFile; // may be null if write failed aoqi@0: } aoqi@0: aoqi@0: public void write(Writer out, ClassSymbol sym) aoqi@0: throws IOException { aoqi@0: lazyInit(); aoqi@0: try { aoqi@0: String cname = mangler.mangle(sym.fullname, Mangle.Type.CLASS); aoqi@0: println(out, fileTop()); aoqi@0: println(out, includes()); aoqi@0: println(out, guardBegin(cname)); aoqi@0: println(out, cppGuardBegin()); aoqi@0: aoqi@0: writeStatics(out, sym); aoqi@0: writeMethods(out, sym, cname); aoqi@0: aoqi@0: println(out, cppGuardEnd()); aoqi@0: println(out, guardEnd(cname)); aoqi@0: } catch (TypeSignature.SignatureException e) { aoqi@0: throw new IOException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected void writeStatics(Writer out, ClassSymbol sym) throws IOException { aoqi@0: List classfields = getAllFields(sym); aoqi@0: aoqi@0: for (VariableElement v: classfields) { aoqi@0: if (!v.getModifiers().contains(Modifier.STATIC)) aoqi@0: continue; aoqi@0: String s = null; aoqi@0: s = defineForStatic(sym, v); aoqi@0: if (s != null) { aoqi@0: println(out, s); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Including super class fields. aoqi@0: */ aoqi@0: List getAllFields(TypeElement subclazz) { aoqi@0: List fields = new ArrayList(); aoqi@0: TypeElement cd = null; aoqi@0: Stack s = new Stack(); aoqi@0: aoqi@0: cd = subclazz; aoqi@0: while (true) { aoqi@0: s.push(cd); aoqi@0: TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass())); aoqi@0: if (c == null) aoqi@0: break; aoqi@0: cd = c; aoqi@0: } aoqi@0: aoqi@0: while (!s.empty()) { aoqi@0: cd = s.pop(); aoqi@0: fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements())); aoqi@0: } aoqi@0: aoqi@0: return fields; aoqi@0: } aoqi@0: aoqi@0: protected String defineForStatic(TypeElement c, VariableElement f) { aoqi@0: CharSequence cnamedoc = c.getQualifiedName(); aoqi@0: CharSequence fnamedoc = f.getSimpleName(); aoqi@0: aoqi@0: String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS); aoqi@0: String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB); aoqi@0: aoqi@0: Assert.check(f.getModifiers().contains(Modifier.STATIC)); aoqi@0: aoqi@0: if (f.getModifiers().contains(Modifier.FINAL)) { aoqi@0: Object value = null; aoqi@0: aoqi@0: value = f.getConstantValue(); aoqi@0: aoqi@0: if (value != null) { /* so it is a ConstantExpression */ aoqi@0: String constString = null; aoqi@0: if ((value instanceof Integer) aoqi@0: || (value instanceof Byte) aoqi@0: || (value instanceof Short)) { aoqi@0: /* covers byte, short, int */ aoqi@0: constString = value.toString() + "L"; aoqi@0: } else if (value instanceof Boolean) { aoqi@0: constString = ((Boolean) value) ? "1L" : "0L"; aoqi@0: } else if (value instanceof Character) { aoqi@0: Character ch = (Character) value; aoqi@0: constString = String.valueOf(((int) ch) & 0xffff) + "L"; aoqi@0: } else if (value instanceof Long) { aoqi@0: // Visual C++ supports the i64 suffix, not LL. aoqi@0: if (isWindows) aoqi@0: constString = value.toString() + "i64"; aoqi@0: else aoqi@0: constString = value.toString() + "LL"; aoqi@0: } else if (value instanceof Float) { aoqi@0: /* bug for bug */ aoqi@0: float fv = ((Float)value).floatValue(); aoqi@0: if (Float.isInfinite(fv)) aoqi@0: constString = ((fv < 0) ? "-" : "") + "Inff"; aoqi@0: else aoqi@0: constString = value.toString() + "f"; aoqi@0: } else if (value instanceof Double) { aoqi@0: /* bug for bug */ aoqi@0: double d = ((Double)value).doubleValue(); aoqi@0: if (Double.isInfinite(d)) aoqi@0: constString = ((d < 0) ? "-" : "") + "InfD"; aoqi@0: else aoqi@0: constString = value.toString(); aoqi@0: } aoqi@0: aoqi@0: if (constString != null) { aoqi@0: StringBuilder s = new StringBuilder("#undef "); aoqi@0: s.append(cname); s.append("_"); s.append(fname); s.append(lineSep); aoqi@0: s.append("#define "); s.append(cname); s.append("_"); aoqi@0: s.append(fname); s.append(" "); s.append(constString); aoqi@0: return s.toString(); aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: protected void writeMethods(Writer out, ClassSymbol sym, String cname) aoqi@0: throws IOException, TypeSignature.SignatureException { aoqi@0: List classmethods = ElementFilter.methodsIn(sym.getEnclosedElements()); aoqi@0: for (ExecutableElement md: classmethods) { aoqi@0: if(md.getModifiers().contains(Modifier.NATIVE)){ aoqi@0: TypeMirror mtr = types.erasure(md.getReturnType()); aoqi@0: String sig = signature(md); aoqi@0: TypeSignature newtypesig = new TypeSignature(elements); aoqi@0: CharSequence methodName = md.getSimpleName(); aoqi@0: boolean longName = false; aoqi@0: for (ExecutableElement md2: classmethods) { aoqi@0: if ((md2 != md) aoqi@0: && (methodName.equals(md2.getSimpleName())) aoqi@0: && (md2.getModifiers().contains(Modifier.NATIVE))) aoqi@0: longName = true; aoqi@0: aoqi@0: } aoqi@0: println(out, "/*"); aoqi@0: println(out, " * Class: " + cname); aoqi@0: println(out, " * Method: " + aoqi@0: mangler.mangle(methodName, Mangle.Type.FIELDSTUB)); aoqi@0: println(out, " * Signature: " + newtypesig.getTypeSignature(sig, mtr)); aoqi@0: println(out, " */"); aoqi@0: println(out, "JNIEXPORT " + jniType(mtr) + aoqi@0: " JNICALL " + aoqi@0: mangler.mangleMethod(md, sym, aoqi@0: (longName) ? aoqi@0: Mangle.Type.METHOD_JNI_LONG : aoqi@0: Mangle.Type.METHOD_JNI_SHORT)); aoqi@0: print(out, " (JNIEnv *, "); aoqi@0: List paramargs = md.getParameters(); aoqi@0: List args = new ArrayList(); aoqi@0: for (VariableElement p: paramargs) { aoqi@0: args.add(types.erasure(p.asType())); aoqi@0: } aoqi@0: if (md.getModifiers().contains(Modifier.STATIC)) aoqi@0: print(out, "jclass"); aoqi@0: else aoqi@0: print(out, "jobject"); aoqi@0: aoqi@0: for (TypeMirror arg: args) { aoqi@0: print(out, ", "); aoqi@0: print(out, jniType(arg)); aoqi@0: } aoqi@0: println(out, ");" aoqi@0: + lineSep); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // c.f. MethodDoc.signature aoqi@0: String signature(ExecutableElement e) { aoqi@0: StringBuilder sb = new StringBuilder("("); aoqi@0: String sep = ""; aoqi@0: for (VariableElement p: e.getParameters()) { aoqi@0: sb.append(sep); aoqi@0: sb.append(types.erasure(p.asType()).toString()); aoqi@0: sep = ","; aoqi@0: } aoqi@0: sb.append(")"); aoqi@0: return sb.toString(); aoqi@0: } aoqi@0: aoqi@0: protected final String jniType(TypeMirror t) { aoqi@0: TypeElement throwable = elements.getTypeElement("java.lang.Throwable"); aoqi@0: TypeElement jClass = elements.getTypeElement("java.lang.Class"); aoqi@0: TypeElement jString = elements.getTypeElement("java.lang.String"); aoqi@0: Element tclassDoc = types.asElement(t); aoqi@0: aoqi@0: aoqi@0: switch (t.getKind()) { aoqi@0: case ARRAY: { aoqi@0: TypeMirror ct = ((ArrayType) t).getComponentType(); aoqi@0: switch (ct.getKind()) { aoqi@0: case BOOLEAN: return "jbooleanArray"; aoqi@0: case BYTE: return "jbyteArray"; aoqi@0: case CHAR: return "jcharArray"; aoqi@0: case SHORT: return "jshortArray"; aoqi@0: case INT: return "jintArray"; aoqi@0: case LONG: return "jlongArray"; aoqi@0: case FLOAT: return "jfloatArray"; aoqi@0: case DOUBLE: return "jdoubleArray"; aoqi@0: case ARRAY: aoqi@0: case DECLARED: return "jobjectArray"; aoqi@0: default: throw new Error(ct.toString()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: case VOID: return "void"; aoqi@0: case BOOLEAN: return "jboolean"; aoqi@0: case BYTE: return "jbyte"; aoqi@0: case CHAR: return "jchar"; aoqi@0: case SHORT: return "jshort"; aoqi@0: case INT: return "jint"; aoqi@0: case LONG: return "jlong"; aoqi@0: case FLOAT: return "jfloat"; aoqi@0: case DOUBLE: return "jdouble"; aoqi@0: aoqi@0: case DECLARED: { aoqi@0: if (tclassDoc.equals(jString)) aoqi@0: return "jstring"; aoqi@0: else if (types.isAssignable(t, throwable.asType())) aoqi@0: return "jthrowable"; aoqi@0: else if (types.isAssignable(t, jClass.asType())) aoqi@0: return "jclass"; aoqi@0: else aoqi@0: return "jobject"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: Assert.check(false, "jni unknown type"); aoqi@0: return null; /* dead code. */ aoqi@0: } aoqi@0: aoqi@0: protected String fileTop() { aoqi@0: return "/* DO NOT EDIT THIS FILE - it is machine generated */"; aoqi@0: } aoqi@0: aoqi@0: protected String includes() { aoqi@0: return "#include "; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Deal with the C pre-processor. aoqi@0: */ aoqi@0: protected String cppGuardBegin() { aoqi@0: return "#ifdef __cplusplus" + lineSep aoqi@0: + "extern \"C\" {" + lineSep aoqi@0: + "#endif"; aoqi@0: } aoqi@0: aoqi@0: protected String cppGuardEnd() { aoqi@0: return "#ifdef __cplusplus" + lineSep aoqi@0: + "}" + lineSep aoqi@0: + "#endif"; aoqi@0: } aoqi@0: aoqi@0: protected String guardBegin(String cname) { aoqi@0: return "/* Header for class " + cname + " */" + lineSep aoqi@0: + lineSep aoqi@0: + "#ifndef _Included_" + cname + lineSep aoqi@0: + "#define _Included_" + cname; aoqi@0: } aoqi@0: aoqi@0: protected String guardEnd(String cname) { aoqi@0: return "#endif"; aoqi@0: } aoqi@0: aoqi@0: protected void print(Writer out, String text) throws IOException { aoqi@0: out.write(text); aoqi@0: } aoqi@0: aoqi@0: protected void println(Writer out, String text) throws IOException { aoqi@0: out.write(text); aoqi@0: out.write(lineSep); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: private static class Mangle { aoqi@0: aoqi@0: public static class Type { aoqi@0: public static final int CLASS = 1; aoqi@0: public static final int FIELDSTUB = 2; aoqi@0: public static final int FIELD = 3; aoqi@0: public static final int JNI = 4; aoqi@0: public static final int SIGNATURE = 5; aoqi@0: public static final int METHOD_JDK_1 = 6; aoqi@0: public static final int METHOD_JNI_SHORT = 7; aoqi@0: public static final int METHOD_JNI_LONG = 8; aoqi@0: }; aoqi@0: aoqi@0: private Elements elems; aoqi@0: private Types types; aoqi@0: aoqi@0: Mangle(Elements elems, Types types) { aoqi@0: this.elems = elems; aoqi@0: this.types = types; aoqi@0: } aoqi@0: aoqi@0: public final String mangle(CharSequence name, int mtype) { aoqi@0: StringBuilder result = new StringBuilder(100); aoqi@0: int length = name.length(); aoqi@0: aoqi@0: for (int i = 0; i < length; i++) { aoqi@0: char ch = name.charAt(i); aoqi@0: if (isalnum(ch)) { aoqi@0: result.append(ch); aoqi@0: } else if ((ch == '.') && aoqi@0: mtype == Mangle.Type.CLASS) { aoqi@0: result.append('_'); aoqi@0: } else if (( ch == '$') && aoqi@0: mtype == Mangle.Type.CLASS) { aoqi@0: result.append('_'); aoqi@0: result.append('_'); aoqi@0: } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) { aoqi@0: result.append('_'); aoqi@0: } else if (ch == '_' && mtype == Mangle.Type.CLASS) { aoqi@0: result.append('_'); aoqi@0: } else if (mtype == Mangle.Type.JNI) { aoqi@0: String esc = null; aoqi@0: if (ch == '_') aoqi@0: esc = "_1"; aoqi@0: else if (ch == '.') aoqi@0: esc = "_"; aoqi@0: else if (ch == ';') aoqi@0: esc = "_2"; aoqi@0: else if (ch == '[') aoqi@0: esc = "_3"; aoqi@0: if (esc != null) { aoqi@0: result.append(esc); aoqi@0: } else { aoqi@0: result.append(mangleChar(ch)); aoqi@0: } aoqi@0: } else if (mtype == Mangle.Type.SIGNATURE) { aoqi@0: if (isprint(ch)) { aoqi@0: result.append(ch); aoqi@0: } else { aoqi@0: result.append(mangleChar(ch)); aoqi@0: } aoqi@0: } else { aoqi@0: result.append(mangleChar(ch)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return result.toString(); aoqi@0: } aoqi@0: aoqi@0: public String mangleMethod(ExecutableElement method, TypeElement clazz, aoqi@0: int mtype) throws TypeSignature.SignatureException { aoqi@0: StringBuilder result = new StringBuilder(100); aoqi@0: result.append("Java_"); aoqi@0: aoqi@0: if (mtype == Mangle.Type.METHOD_JDK_1) { aoqi@0: result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS)); aoqi@0: result.append('_'); aoqi@0: result.append(mangle(method.getSimpleName(), aoqi@0: Mangle.Type.FIELD)); aoqi@0: result.append("_stub"); aoqi@0: return result.toString(); aoqi@0: } aoqi@0: aoqi@0: /* JNI */ aoqi@0: result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI)); aoqi@0: result.append('_'); aoqi@0: result.append(mangle(method.getSimpleName(), aoqi@0: Mangle.Type.JNI)); aoqi@0: if (mtype == Mangle.Type.METHOD_JNI_LONG) { aoqi@0: result.append("__"); aoqi@0: String typesig = signature(method); aoqi@0: TypeSignature newTypeSig = new TypeSignature(elems); aoqi@0: String sig = newTypeSig.getTypeSignature(typesig, method.getReturnType()); aoqi@0: sig = sig.substring(1); aoqi@0: sig = sig.substring(0, sig.lastIndexOf(')')); aoqi@0: sig = sig.replace('/', '.'); aoqi@0: result.append(mangle(sig, Mangle.Type.JNI)); aoqi@0: } aoqi@0: aoqi@0: return result.toString(); aoqi@0: } aoqi@0: //where aoqi@0: private String getInnerQualifiedName(TypeElement clazz) { aoqi@0: return elems.getBinaryName(clazz).toString(); aoqi@0: } aoqi@0: aoqi@0: public final String mangleChar(char ch) { aoqi@0: String s = Integer.toHexString(ch); aoqi@0: int nzeros = 5 - s.length(); aoqi@0: char[] result = new char[6]; aoqi@0: result[0] = '_'; aoqi@0: for (int i = 1; i <= nzeros; i++) aoqi@0: result[i] = '0'; aoqi@0: for (int i = nzeros+1, j = 0; i < 6; i++, j++) aoqi@0: result[i] = s.charAt(j); aoqi@0: return new String(result); aoqi@0: } aoqi@0: aoqi@0: // Warning: duplicated in Gen aoqi@0: private String signature(ExecutableElement e) { aoqi@0: StringBuilder sb = new StringBuilder(); aoqi@0: String sep = "("; aoqi@0: for (VariableElement p: e.getParameters()) { aoqi@0: sb.append(sep); aoqi@0: sb.append(types.erasure(p.asType()).toString()); aoqi@0: sep = ","; aoqi@0: } aoqi@0: sb.append(")"); aoqi@0: return sb.toString(); aoqi@0: } aoqi@0: aoqi@0: /* Warning: Intentional ASCII operation. */ aoqi@0: private static boolean isalnum(char ch) { aoqi@0: return ch <= 0x7f && /* quick test */ aoqi@0: ((ch >= 'A' && ch <= 'Z') || aoqi@0: (ch >= 'a' && ch <= 'z') || aoqi@0: (ch >= '0' && ch <= '9')); aoqi@0: } aoqi@0: aoqi@0: /* Warning: Intentional ASCII operation. */ aoqi@0: private static boolean isprint(char ch) { aoqi@0: return ch >= 32 && ch <= 126; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static class TypeSignature { aoqi@0: static class SignatureException extends Exception { aoqi@0: private static final long serialVersionUID = 1L; aoqi@0: SignatureException(String reason) { aoqi@0: super(reason); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: Elements elems; aoqi@0: aoqi@0: /* Signature Characters */ aoqi@0: aoqi@0: private static final String SIG_VOID = "V"; aoqi@0: private static final String SIG_BOOLEAN = "Z"; aoqi@0: private static final String SIG_BYTE = "B"; aoqi@0: private static final String SIG_CHAR = "C"; aoqi@0: private static final String SIG_SHORT = "S"; aoqi@0: private static final String SIG_INT = "I"; aoqi@0: private static final String SIG_LONG = "J"; aoqi@0: private static final String SIG_FLOAT = "F"; aoqi@0: private static final String SIG_DOUBLE = "D"; aoqi@0: private static final String SIG_ARRAY = "["; aoqi@0: private static final String SIG_CLASS = "L"; aoqi@0: aoqi@0: aoqi@0: aoqi@0: public TypeSignature(Elements elems){ aoqi@0: this.elems = elems; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Returns the type signature of a field according to JVM specs aoqi@0: */ aoqi@0: public String getTypeSignature(String javasignature) throws SignatureException { aoqi@0: return getParamJVMSignature(javasignature); aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Returns the type signature of a method according to JVM specs aoqi@0: */ aoqi@0: public String getTypeSignature(String javasignature, TypeMirror returnType) aoqi@0: throws SignatureException { aoqi@0: String signature = null; //Java type signature. aoqi@0: String typeSignature = null; //Internal type signature. aoqi@0: List params = new ArrayList(); //List of parameters. aoqi@0: String paramsig = null; //Java parameter signature. aoqi@0: String paramJVMSig = null; //Internal parameter signature. aoqi@0: String returnSig = null; //Java return type signature. aoqi@0: String returnJVMType = null; //Internal return type signature. aoqi@0: int dimensions = 0; //Array dimension. aoqi@0: aoqi@0: int startIndex = -1; aoqi@0: int endIndex = -1; aoqi@0: StringTokenizer st = null; aoqi@0: int i = 0; aoqi@0: aoqi@0: // Gets the actual java signature without parentheses. aoqi@0: if (javasignature != null) { aoqi@0: startIndex = javasignature.indexOf("("); aoqi@0: endIndex = javasignature.indexOf(")"); aoqi@0: } aoqi@0: aoqi@0: if (((startIndex != -1) && (endIndex != -1)) aoqi@0: &&(startIndex+1 < javasignature.length()) aoqi@0: &&(endIndex < javasignature.length())) { aoqi@0: signature = javasignature.substring(startIndex+1, endIndex); aoqi@0: } aoqi@0: aoqi@0: // Separates parameters. aoqi@0: if (signature != null) { aoqi@0: if (signature.indexOf(",") != -1) { aoqi@0: st = new StringTokenizer(signature, ","); aoqi@0: if (st != null) { aoqi@0: while (st.hasMoreTokens()) { aoqi@0: params.add(st.nextToken()); aoqi@0: } aoqi@0: } aoqi@0: } else { aoqi@0: params.add(signature); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /* JVM type signature. */ aoqi@0: typeSignature = "("; aoqi@0: aoqi@0: // Gets indivisual internal parameter signature. aoqi@0: while (params.isEmpty() != true) { aoqi@0: paramsig = params.remove(i).trim(); aoqi@0: paramJVMSig = getParamJVMSignature(paramsig); aoqi@0: if (paramJVMSig != null) { aoqi@0: typeSignature += paramJVMSig; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: typeSignature += ")"; aoqi@0: aoqi@0: // Get internal return type signature. aoqi@0: aoqi@0: returnJVMType = ""; aoqi@0: if (returnType != null) { aoqi@0: dimensions = dimensions(returnType); aoqi@0: } aoqi@0: aoqi@0: //Gets array dimension of return type. aoqi@0: while (dimensions-- > 0) { aoqi@0: returnJVMType += "["; aoqi@0: } aoqi@0: if (returnType != null) { aoqi@0: returnSig = qualifiedTypeName(returnType); aoqi@0: returnJVMType += getComponentType(returnSig); aoqi@0: } else { aoqi@0: System.out.println("Invalid return type."); aoqi@0: } aoqi@0: aoqi@0: typeSignature += returnJVMType; aoqi@0: aoqi@0: return typeSignature; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Returns internal signature of a parameter. aoqi@0: */ aoqi@0: private String getParamJVMSignature(String paramsig) throws SignatureException { aoqi@0: String paramJVMSig = ""; aoqi@0: String componentType =""; aoqi@0: aoqi@0: if(paramsig != null){ aoqi@0: aoqi@0: if(paramsig.indexOf("[]") != -1) { aoqi@0: // Gets array dimension. aoqi@0: int endindex = paramsig.indexOf("[]"); aoqi@0: componentType = paramsig.substring(0, endindex); aoqi@0: String dimensionString = paramsig.substring(endindex); aoqi@0: if(dimensionString != null){ aoqi@0: while(dimensionString.indexOf("[]") != -1){ aoqi@0: paramJVMSig += "["; aoqi@0: int beginindex = dimensionString.indexOf("]") + 1; aoqi@0: if(beginindex < dimensionString.length()){ aoqi@0: dimensionString = dimensionString.substring(beginindex); aoqi@0: }else aoqi@0: dimensionString = ""; aoqi@0: } aoqi@0: } aoqi@0: } else componentType = paramsig; aoqi@0: aoqi@0: paramJVMSig += getComponentType(componentType); aoqi@0: } aoqi@0: return paramJVMSig; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Returns internal signature of a component. aoqi@0: */ aoqi@0: private String getComponentType(String componentType) throws SignatureException { aoqi@0: aoqi@0: String JVMSig = ""; aoqi@0: aoqi@0: if(componentType != null){ aoqi@0: if(componentType.equals("void")) JVMSig += SIG_VOID ; aoqi@0: else if(componentType.equals("boolean")) JVMSig += SIG_BOOLEAN ; aoqi@0: else if(componentType.equals("byte")) JVMSig += SIG_BYTE ; aoqi@0: else if(componentType.equals("char")) JVMSig += SIG_CHAR ; aoqi@0: else if(componentType.equals("short")) JVMSig += SIG_SHORT ; aoqi@0: else if(componentType.equals("int")) JVMSig += SIG_INT ; aoqi@0: else if(componentType.equals("long")) JVMSig += SIG_LONG ; aoqi@0: else if(componentType.equals("float")) JVMSig += SIG_FLOAT ; aoqi@0: else if(componentType.equals("double")) JVMSig += SIG_DOUBLE ; aoqi@0: else { aoqi@0: if(!componentType.equals("")){ aoqi@0: TypeElement classNameDoc = elems.getTypeElement(componentType); aoqi@0: aoqi@0: if(classNameDoc == null){ aoqi@0: throw new SignatureException(componentType); aoqi@0: }else { aoqi@0: String classname = classNameDoc.getQualifiedName().toString(); aoqi@0: String newclassname = classname.replace('.', '/'); aoqi@0: JVMSig += "L"; aoqi@0: JVMSig += newclassname; aoqi@0: JVMSig += ";"; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return JVMSig; aoqi@0: } aoqi@0: aoqi@0: int dimensions(TypeMirror t) { aoqi@0: if (t.getKind() != TypeKind.ARRAY) aoqi@0: return 0; aoqi@0: return 1 + dimensions(((ArrayType) t).getComponentType()); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: String qualifiedTypeName(TypeMirror type) { aoqi@0: TypeVisitor v = new SimpleTypeVisitor8() { aoqi@0: @Override aoqi@0: public Name visitArray(ArrayType t, Void p) { aoqi@0: return t.getComponentType().accept(this, p); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Name visitDeclared(DeclaredType t, Void p) { aoqi@0: return ((TypeElement) t.asElement()).getQualifiedName(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Name visitPrimitive(PrimitiveType t, Void p) { aoqi@0: return elems.getName(t.toString()); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Name visitNoType(NoType t, Void p) { aoqi@0: if (t.getKind() == TypeKind.VOID) aoqi@0: return elems.getName("void"); aoqi@0: return defaultAction(t, p); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Name visitTypeVariable(TypeVariable t, Void p) { aoqi@0: return t.getUpperBound().accept(this, p); aoqi@0: } aoqi@0: }; aoqi@0: return v.visit(type).toString(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: }