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

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