JNIWriter.java revision 3770:d813bfb238a9
117680Spst/*
298527Sfenner * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
398527Sfenner * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
498527Sfenner *
598527Sfenner * This code is free software; you can redistribute it and/or modify it
698527Sfenner * under the terms of the GNU General Public License version 2 only, as
798527Sfenner * published by the Free Software Foundation.  Oracle designates this
898527Sfenner * particular file as subject to the "Classpath" exception as provided
998527Sfenner * by Oracle in the LICENSE file that accompanied this code.
1098527Sfenner *
1198527Sfenner * This code is distributed in the hope that it will be useful, but WITHOUT
1298527Sfenner * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1398527Sfenner * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1498527Sfenner * version 2 for more details (a copy is included in the LICENSE file that
1598527Sfenner * accompanied this code).
1698527Sfenner *
1798527Sfenner * You should have received a copy of the GNU General Public License version
1898527Sfenner * 2 along with this work; if not, write to the Free Software Foundation,
1998527Sfenner * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2098527Sfenner *
2198527Sfenner * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2298527Sfenner * or visit www.oracle.com if you need additional information or have any
2398527Sfenner * questions.
2498527Sfenner */
2598527Sfenner
2698527Sfennerpackage com.sun.tools.javac.jvm;
2798527Sfenner
2898527Sfennerimport java.io.IOException;
2998527Sfennerimport java.io.PrintWriter;
3098527Sfennerimport java.util.ArrayList;
3198527Sfennerimport java.util.Collections;
3298527Sfennerimport java.util.List;
3398527Sfenner
3498527Sfennerimport javax.tools.FileObject;
3517680Spstimport javax.tools.JavaFileManager;
3617680Spstimport javax.tools.JavaFileManager.Location;
3717680Spstimport javax.tools.StandardLocation;
3817680Spst
3917680Spstimport com.sun.tools.javac.code.Attribute;
4017680Spstimport com.sun.tools.javac.code.Flags;
4156896Sfennerimport com.sun.tools.javac.code.Symbol;
4256896Sfennerimport com.sun.tools.javac.code.Symbol.ClassSymbol;
4317680Spstimport com.sun.tools.javac.code.Symbol.ModuleSymbol;
4417680Spstimport com.sun.tools.javac.code.Symbol.VarSymbol;
4526183Sfennerimport com.sun.tools.javac.code.Symtab;
46127675Sbmsimport com.sun.tools.javac.code.Type;
47127675Sbmsimport com.sun.tools.javac.code.Types;
4826183Sfennerimport com.sun.tools.javac.model.JavacElements;
4926183Sfennerimport com.sun.tools.javac.util.Assert;
5056896Sfennerimport com.sun.tools.javac.util.Context;
5156896Sfennerimport com.sun.tools.javac.util.Log;
5256896Sfennerimport com.sun.tools.javac.util.Options;
5356896Sfennerimport com.sun.tools.javac.util.Pair;
54127675Sbms
5517680Spstimport static com.sun.tools.javac.main.Option.*;
5617680Spstimport static com.sun.tools.javac.code.Kinds.Kind.*;
5717680Spstimport static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
5817680Spst
5917680Spst/** This class provides operations to write native header files for classes.
6017680Spst *
6117680Spst *  <p><b>This is NOT part of any supported API.
6217680Spst *  If you write code that depends on this, you do so at your own risk.
6317680Spst *  This code and its internal interfaces are subject to change or
6417680Spst *  deletion without notice.</b>
6517680Spst */
6617680Spstpublic class JNIWriter {
6717680Spst    protected static final Context.Key<JNIWriter> jniWriterKey = new Context.Key<>();
6817680Spst
6917680Spst    /** Access to files. */
7017680Spst    private final JavaFileManager fileManager;
7117680Spst
7217680Spst    Types      types;
7317680Spst    Symtab     syms;
7417680Spst
7517680Spst    /** The log to use for verbose output.
7617680Spst     */
7717680Spst    private final Log log;
7817680Spst
7917680Spst    /** Switch: verbose output.
8017680Spst     */
8117680Spst    private boolean verbose;
8217680Spst
8317680Spst    /** Switch: check all nested classes of top level class
8417680Spst     */
8517680Spst    private boolean checkAll;
8617680Spst
8717680Spst    /**
8817680Spst     * If true, class files will be written in module-specific subdirectories
8917680Spst     * of the NATIVE_HEADER_OUTPUT location.
9017680Spst     */
9117680Spst    public boolean multiModuleMode;
9217680Spst
9317680Spst    private Context context;
9417680Spst
9517680Spst    private static final boolean isWindows =
9617680Spst        System.getProperty("os.name").startsWith("Windows");
9717680Spst
9817680Spst    /** Get the ClassWriter instance for this context. */
9917680Spst    public static JNIWriter instance(Context context) {
10017680Spst        JNIWriter instance = context.get(jniWriterKey);
10117680Spst        if (instance == null)
10217680Spst            instance = new JNIWriter(context);
10317680Spst        return instance;
10417680Spst    }
10517680Spst
10617680Spst    /** Construct a class writer, given an options table.
10717680Spst     */
10817680Spst    private JNIWriter(Context context) {
10917680Spst        context.put(jniWriterKey, this);
11017680Spst        fileManager = context.get(JavaFileManager.class);
111127675Sbms        log = Log.instance(context);
11217680Spst
11317680Spst        Options options = Options.instance(context);
11418976Sdfr        verbose = options.isSet(VERBOSE);
115127675Sbms        checkAll = options.isSet("javah:full");
11618976Sdfr
11717680Spst        this.context = context; // for lazyInit()
11817680Spst    }
11998527Sfenner
12098527Sfenner    private void lazyInit() {
12117680Spst        if (types == null)
12217680Spst            types = Types.instance(context);
123127675Sbms        if (syms == null)
12417680Spst            syms = Symtab.instance(context);
12517680Spst
12675118Sfenner    }
12717680Spst
12817680Spst    static boolean isSynthetic(Symbol s) {
12917680Spst        return hasFlag(s, Flags.SYNTHETIC);
13017680Spst    }
13117680Spst    static boolean isStatic(Symbol s) {
13217680Spst        return hasFlag(s, Flags.STATIC);
13317680Spst    }
13417680Spst    static boolean isFinal(Symbol s) {
13517680Spst        return hasFlag(s, Flags.FINAL);
13617680Spst    }
13717680Spst    static boolean isNative(Symbol s) {
13817680Spst        return hasFlag(s, Flags.NATIVE);
13917680Spst    }
14017680Spst    static private boolean hasFlag(Symbol m, int flag) {
14117680Spst        return (m.flags() & flag) != 0;
14217680Spst    }
14317680Spst
14417680Spst    public boolean needsHeader(ClassSymbol c) {
14517680Spst        lazyInit();
14617680Spst        if (c.isLocal() || isSynthetic(c))
14717680Spst            return false;
14817680Spst        return (checkAll)
14917680Spst                ? needsHeader(c.outermostClass(), true)
15017680Spst                : needsHeader(c, false);
15117680Spst    }
15217680Spst
15317680Spst    private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) {
15417680Spst        if (c.isLocal() || isSynthetic(c))
15517680Spst            return false;
15617680Spst
15717680Spst        for (Symbol sym : c.members_field.getSymbols(NON_RECURSIVE)) {
15817680Spst            if (sym.kind == MTH && isNative(sym))
15917680Spst                return true;
16017680Spst            for (Attribute.Compound a: sym.getDeclarationAttributes()) {
16117680Spst                if (a.type.tsym == syms.nativeHeaderType.tsym)
16217680Spst                    return true;
16317680Spst            }
16417680Spst        }
16517680Spst        if (checkNestedClasses) {
16617680Spst            for (Symbol sym : c.members_field.getSymbols(NON_RECURSIVE)) {
16717680Spst                if ((sym.kind == TYP) && needsHeader(((ClassSymbol) sym), true))
16817680Spst                    return true;
16917680Spst            }
17017680Spst        }
17117680Spst        return false;
17217680Spst    }
17317680Spst
17417680Spst    /** Emit a class file for a given class.
17517680Spst     *  @param c      The class from which a class file is generated.
17617680Spst     */
17717680Spst    public FileObject write(ClassSymbol c) throws IOException {
17817680Spst        String className = c.flatName().toString();
17917680Spst        Location outLocn;
18017680Spst        if (multiModuleMode) {
18117680Spst            ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
18217680Spst            outLocn = fileManager.getLocationForModule(StandardLocation.NATIVE_HEADER_OUTPUT, msym.name.toString());
18317680Spst        } else {
18417680Spst            outLocn = StandardLocation.NATIVE_HEADER_OUTPUT;
18517680Spst        }
18617680Spst        FileObject outFile
18717680Spst            = fileManager.getFileForOutput(outLocn,
18817680Spst                "", className.replaceAll("[.$]", "_") + ".h", null);
18917680Spst        PrintWriter out = new PrintWriter(outFile.openWriter());
19017680Spst        try {
19117680Spst            write(out, c);
19217680Spst            if (verbose)
19317680Spst                log.printVerbose("wrote.file", outFile);
19417680Spst            out.close();
19517680Spst            out = null;
19617680Spst        } finally {
19717680Spst            if (out != null) {
19817680Spst                // if we are propogating an exception, delete the file
19917680Spst                out.close();
20017680Spst                outFile.delete();
20117680Spst                outFile = null;
20217680Spst            }
20317680Spst        }
20417680Spst        return outFile; // may be null if write failed
20517680Spst    }
20617680Spst
20717680Spst    public void write(PrintWriter out, ClassSymbol sym) throws IOException {
20817680Spst        lazyInit();
20917680Spst        try {
21017680Spst            String cname = encode(sym.fullname, EncoderType.CLASS);
21117680Spst            fileTop(out);
21217680Spst            includes(out);
21317680Spst            guardBegin(out, cname);
21417680Spst            cppGuardBegin(out);
21517680Spst
21617680Spst            writeStatics(out, sym);
21717680Spst            writeMethods(out, sym, cname);
21817680Spst
21917680Spst            cppGuardEnd(out);
22017680Spst            guardEnd(out);
22117680Spst        } catch (TypeSignature.SignatureException e) {
22217680Spst            throw new IOException(e);
22317680Spst        }
22417680Spst    }
22517680Spst    protected void writeStatics(PrintWriter out, ClassSymbol sym) throws IOException {
22617680Spst        List<ClassSymbol> clist = new ArrayList<>();
22717680Spst        for (ClassSymbol cd = sym; cd != null;
22817680Spst                cd = (ClassSymbol) cd.getSuperclass().tsym) {
22917680Spst            clist.add(cd);
23017680Spst        }
23117680Spst        /*
23217680Spst         * list needs to be super-class, base-class1, base-class2 and so on,
23317680Spst         * so we reverse class hierarchy
23417680Spst         */
23517680Spst        Collections.reverse(clist);
23617680Spst        for (ClassSymbol cd : clist) {
23717680Spst            for (Symbol i : cd.getEnclosedElements()) {
23817680Spst                // consider only final, static and fields with ConstantExpressions
23917680Spst                if (isFinal(i) && i.isStatic() && i.kind == VAR) {
24017680Spst                    VarSymbol v = (VarSymbol) i;
24117680Spst                    if (v.getConstantValue() != null) {
24217680Spst                        Pair<ClassSymbol, VarSymbol> p = new Pair<>(sym, v);
24317680Spst                        printStaticDefines(out, p);
24417680Spst                    }
24517680Spst                }
24617680Spst            }
24717680Spst        }
24817680Spst    }
24917680Spst    static void printStaticDefines(PrintWriter out, Pair<ClassSymbol, VarSymbol> p) {
25017680Spst        ClassSymbol cls = p.fst;
25117680Spst        VarSymbol f = p.snd;
25217680Spst        Object value = f.getConstantValue();
25317680Spst        String valueStr = null;
25417680Spst        switch (f.asType().getKind()) {
25517680Spst            case BOOLEAN:
25617680Spst                valueStr = (((Boolean) value) ? "1L" : "0L");
25726183Sfenner                break;
25826183Sfenner            case BYTE: case SHORT: case INT:
25917680Spst                valueStr = value.toString() + "L";
26017680Spst                break;
26117680Spst            case LONG:
26217680Spst                // Visual C++ supports the i64 suffix, not LL.
26317680Spst                valueStr = value.toString() + ((isWindows) ? "i64" : "LL");
26417680Spst                break;
26517680Spst            case CHAR:
26617680Spst                Character ch = (Character) value;
26717680Spst                valueStr = String.valueOf(((int) ch) & 0xffff) + "L";
26817680Spst                break;
26917680Spst            case FLOAT:
27017680Spst                // bug compatible
27117680Spst                float fv = ((Float) value).floatValue();
27217680Spst                valueStr = (Float.isInfinite(fv))
27326183Sfenner                        ? ((fv < 0) ? "-" : "") + "Inff"
27426183Sfenner                        : value.toString() + "f";
27517680Spst                break;
27617680Spst            case DOUBLE:
27717680Spst                // bug compatible
27817680Spst                double d = ((Double) value).doubleValue();
27917680Spst                valueStr = (Double.isInfinite(d))
28017680Spst                        ? ((d < 0) ? "-" : "") + "InfD"
28117680Spst                        : value.toString();
28217680Spst                break;
28326183Sfenner            default:
28426183Sfenner                valueStr = null;
28517680Spst        }
28617680Spst        if (valueStr != null) {
28717680Spst            out.print("#undef ");
28817680Spst            String cname = encode(cls.getQualifiedName(), EncoderType.CLASS);
28917680Spst            String fname = encode(f.getSimpleName(), EncoderType.FIELDSTUB);
29017680Spst            out.println(cname + "_" + fname);
29117680Spst            out.print("#define " + cname + "_");
29217680Spst            out.println(fname + " " + valueStr);
29317680Spst        }
29417680Spst    }
29526183Sfenner    protected void writeMethods(PrintWriter out, ClassSymbol sym, String cname)
29626183Sfenner            throws IOException, TypeSignature.SignatureException {
29717680Spst        List<Symbol> classmethods = sym.getEnclosedElements();
29817680Spst        for (Symbol md : classmethods) {
29917680Spst            if (isNative(md)) {
30017680Spst                TypeSignature newtypesig = new TypeSignature(types);
30117680Spst                CharSequence methodName = md.getSimpleName();
30217680Spst                boolean isOverloaded = false;
30317680Spst                for (Symbol md2 : classmethods) {
30417680Spst                    if ((md2 != md)
30517680Spst                            && (methodName.equals(md2.getSimpleName()))
30617680Spst                            && isNative(md2)) {
30717680Spst                        isOverloaded = true;
30817680Spst                    }
30917680Spst                }
31017680Spst                out.println("/*");
31117680Spst                out.println(" * Class:     " + cname);
31226183Sfenner                out.println(" * Method:    " + encode(methodName, EncoderType.FIELDSTUB));
31326183Sfenner                out.println(" * Signature: " + newtypesig.getSignature(md.type));
31417680Spst                out.println(" */");
31517680Spst                out.println("JNIEXPORT " + jniType(types.erasure(md.type.getReturnType()))
31617680Spst                        + " JNICALL " + encodeMethod(md, sym, isOverloaded));
31717680Spst                out.print("  (JNIEnv *, ");
31817680Spst                out.print((md.isStatic())
31917680Spst                        ? "jclass"
32017680Spst                        : "jobject");
32117680Spst                for (Type arg : types.erasure(md.type.getParameterTypes())) {
32217680Spst                    out.print(", ");
32317680Spst                    out.print(jniType(arg));
32417680Spst                }
32526183Sfenner                out.println(");");
32617680Spst                out.println();
32726183Sfenner            }
32817680Spst        }
32917680Spst    }
33017680Spst    @SuppressWarnings("fallthrough")
33117680Spst    protected final String jniType(Type t) {
33217680Spst        switch (t.getKind()) {
33317680Spst            case ARRAY: {
33417680Spst                Type ct = ((Type.ArrayType)t).getComponentType();
33517680Spst                switch (ct.getKind()) {
33617680Spst                    case BOOLEAN:  return "jbooleanArray";
33717680Spst                    case BYTE:     return "jbyteArray";
33817680Spst                    case CHAR:     return "jcharArray";
33926183Sfenner                    case SHORT:    return "jshortArray";
34026183Sfenner                    case INT:      return "jintArray";
34117680Spst                    case LONG:     return "jlongArray";
34217680Spst                    case FLOAT:    return "jfloatArray";
34317680Spst                    case DOUBLE:   return "jdoubleArray";
34417680Spst                    case ARRAY:
34517680Spst                    case DECLARED: return "jobjectArray";
34617680Spst                    default: throw new Error(ct.toString());
34717680Spst                }
34817680Spst            }
34917680Spst
35017680Spst            case VOID:     return "void";
35117680Spst            case BOOLEAN:  return "jboolean";
35217680Spst            case BYTE:     return "jbyte";
35339300Sfenner            case CHAR:     return "jchar";
35439300Sfenner            case SHORT:    return "jshort";
35517680Spst            case INT:      return "jint";
35617680Spst            case LONG:     return "jlong";
35717680Spst            case FLOAT:    return "jfloat";
35817680Spst            case DOUBLE:   return "jdouble";
35917680Spst            case DECLARED: {
36039300Sfenner                if (t.tsym.type == syms.stringType) {
36126183Sfenner                    return "jstring";
36226183Sfenner                } else if (types.isAssignable(t, syms.throwableType)) {
36317680Spst                    return "jthrowable";
36417680Spst                } else if (types.isAssignable(t, syms.classType)) {
36517680Spst                    return "jclass";
36617680Spst                } else {
36717680Spst                    return "jobject";
36817680Spst                }
36917680Spst            }
37017680Spst        }
37117680Spst
37217680Spst        Assert.check(false, "jni unknown type");
37317680Spst        return null; /* dead code. */
37417680Spst    }
37517680Spst
37617680Spst    protected void  fileTop(PrintWriter out) {
37717680Spst        out.println("/* DO NOT EDIT THIS FILE - it is machine generated */");
37826183Sfenner    }
37926183Sfenner
38017680Spst    protected void includes(PrintWriter out) {
38117680Spst        out.println("#include <jni.h>");
38217680Spst    }
38317680Spst
38417680Spst    /*
38517680Spst     * Deal with the C pre-processor.
38617680Spst     */
38717680Spst    protected void cppGuardBegin(PrintWriter out) {
38817680Spst        out.println("#ifdef __cplusplus");
38917680Spst        out.println("extern \"C\" {");
39026183Sfenner        out.println("#endif");
39117680Spst    }
39226183Sfenner
39317680Spst    protected void cppGuardEnd(PrintWriter out) {
39417680Spst        out.println("#ifdef __cplusplus");
39517680Spst        out.println("}");
39617680Spst        out.println("#endif");
39717680Spst    }
39817680Spst
39917680Spst    protected void guardBegin(PrintWriter out, String cname) {
40017680Spst        out.println("/* Header for class " + cname + " */");
40117680Spst        out.println();
40217680Spst        out.println("#ifndef _Included_" + cname);
40317680Spst        out.println("#define _Included_" + cname);
40475118Sfenner    }
40575118Sfenner
40675118Sfenner    protected void guardEnd(PrintWriter out) {
40775118Sfenner        out.println("#endif");
40817680Spst    }
40975118Sfenner
41075118Sfenner    String encodeMethod(Symbol msym, ClassSymbol clazz,
41198527Sfenner            boolean isOverloaded) throws TypeSignature.SignatureException {
41275118Sfenner        StringBuilder result = new StringBuilder(100);
41398527Sfenner        result.append("Java_");
41417680Spst        /* JNI */
41526183Sfenner        result.append(encode(clazz.flatname.toString(), EncoderType.JNI));
41626183Sfenner        result.append('_');
41717680Spst        result.append(encode(msym.getSimpleName(), EncoderType.JNI));
41817680Spst        if (isOverloaded) {
41917680Spst            TypeSignature typeSig = new TypeSignature(types);
42017680Spst            StringBuilder sig = typeSig.getParameterSignature(msym.type);
42117680Spst            result.append("__").append(encode(sig, EncoderType.JNI));
42217680Spst        }
42317680Spst        return result.toString();
42417680Spst    }
42517680Spst
42617680Spst    static enum EncoderType {
42717680Spst        CLASS,
42817680Spst        FIELDSTUB,
42917680Spst        FIELD,
43017680Spst        JNI,
43117680Spst        SIGNATURE
43217680Spst    }
43317680Spst    @SuppressWarnings("fallthrough")
43417680Spst    static String encode(CharSequence name, EncoderType mtype) {
43517680Spst        StringBuilder result = new StringBuilder(100);
43617680Spst        int length = name.length();
43717680Spst
43817680Spst        for (int i = 0; i < length; i++) {
439127675Sbms            char ch = name.charAt(i);
44017680Spst            if (isalnum(ch)) {
44117680Spst                result.append(ch);
44217680Spst                continue;
44317680Spst            }
44417680Spst            switch (mtype) {
44517680Spst                case CLASS:
44617680Spst                    switch (ch) {
44717680Spst                        case '.':
44817680Spst                        case '_':
44917680Spst                            result.append("_");
45017680Spst                            break;
45117680Spst                        case '$':
45217680Spst                            result.append("__");
45317680Spst                            break;
45417680Spst                        default:
45517680Spst                            result.append(encodeChar(ch));
45617680Spst                    }
45717680Spst                    break;
45817680Spst                case JNI:
45917680Spst                    switch (ch) {
46017680Spst                        case '/':
461                        case '.':
462                            result.append("_");
463                            break;
464                        case '_':
465                            result.append("_1");
466                            break;
467                        case ';':
468                            result.append("_2");
469                            break;
470                        case '[':
471                            result.append("_3");
472                            break;
473                        default:
474                            result.append(encodeChar(ch));
475                    }
476                    break;
477                case SIGNATURE:
478                    result.append(isprint(ch) ? ch : encodeChar(ch));
479                    break;
480                case FIELDSTUB:
481                    result.append(ch == '_' ? ch : encodeChar(ch));
482                    break;
483                default:
484                    result.append(encodeChar(ch));
485            }
486        }
487        return result.toString();
488    }
489
490    static String encodeChar(char ch) {
491        String s = Integer.toHexString(ch);
492        int nzeros = 5 - s.length();
493        char[] result = new char[6];
494        result[0] = '_';
495        for (int i = 1; i <= nzeros; i++) {
496            result[i] = '0';
497        }
498        for (int i = nzeros + 1, j = 0; i < 6; i++, j++) {
499            result[i] = s.charAt(j);
500        }
501        return new String(result);
502    }
503
504    /* Warning: Intentional ASCII operation. */
505    private static boolean isalnum(char ch) {
506        return ch <= 0x7f && /* quick test */
507                ((ch >= 'A' && ch <= 'Z')  ||
508                 (ch >= 'a' && ch <= 'z')  ||
509                 (ch >= '0' && ch <= '9'));
510    }
511
512    /* Warning: Intentional ASCII operation. */
513    private static boolean isprint(char ch) {
514        return ch >= 32 && ch <= 126;
515    }
516
517    private static class TypeSignature {
518        static class SignatureException extends Exception {
519            private static final long serialVersionUID = 1L;
520            SignatureException(String reason) {
521                super(reason);
522            }
523        }
524
525        JavacElements elems;
526        Types    types;
527
528        /* Signature Characters */
529        private static final String SIG_VOID                   = "V";
530        private static final String SIG_BOOLEAN                = "Z";
531        private static final String SIG_BYTE                   = "B";
532        private static final String SIG_CHAR                   = "C";
533        private static final String SIG_SHORT                  = "S";
534        private static final String SIG_INT                    = "I";
535        private static final String SIG_LONG                   = "J";
536        private static final String SIG_FLOAT                  = "F";
537        private static final String SIG_DOUBLE                 = "D";
538        private static final String SIG_ARRAY                  = "[";
539        private static final String SIG_CLASS                  = "L";
540
541        public TypeSignature(Types types) {
542            this.types = types;
543        }
544
545        StringBuilder getParameterSignature(Type mType)
546                throws SignatureException {
547            StringBuilder result = new StringBuilder();
548            for (Type pType : mType.getParameterTypes()) {
549                result.append(getJvmSignature(pType));
550            }
551            return result;
552        }
553
554        StringBuilder getReturnSignature(Type mType)
555                throws SignatureException {
556            return getJvmSignature(mType.getReturnType());
557        }
558
559        StringBuilder getSignature(Type mType) throws SignatureException {
560            StringBuilder sb = new StringBuilder();
561            sb.append("(").append(getParameterSignature(mType)).append(")");
562            sb.append(getReturnSignature(mType));
563            return sb;
564        }
565
566        /*
567         * Returns jvm internal signature.
568         */
569        static class JvmTypeVisitor extends JNIWriter.SimpleTypeVisitor<Type, StringBuilder> {
570
571            @Override
572            public Type visitClassType(Type.ClassType t, StringBuilder s) {
573                setDeclaredType(t, s);
574                return null;
575            }
576
577            @Override
578            public Type visitArrayType(Type.ArrayType t, StringBuilder s) {
579                s.append("[");
580                return t.getComponentType().accept(this, s);
581            }
582
583            @Override
584            public Type visitType(Type t, StringBuilder s) {
585                if (t.isPrimitiveOrVoid()) {
586                    s.append(getJvmPrimitiveSignature(t));
587                    return null;
588                }
589                return t.accept(this, s);
590            }
591            private void setDeclaredType(Type t, StringBuilder s) {
592                    String classname = t.tsym.getQualifiedName().toString();
593                    classname = classname.replace('.', '/');
594                    s.append("L").append(classname).append(";");
595            }
596            private String getJvmPrimitiveSignature(Type t) {
597                switch (t.getKind()) {
598                    case VOID:      return SIG_VOID;
599                    case BOOLEAN:   return SIG_BOOLEAN;
600                    case BYTE:      return SIG_BYTE;
601                    case CHAR:      return SIG_CHAR;
602                    case SHORT:     return SIG_SHORT;
603                    case INT:       return SIG_INT;
604                    case LONG:      return SIG_LONG;
605                    case FLOAT:     return SIG_FLOAT;
606                    case DOUBLE:    return SIG_DOUBLE;
607                    default:
608                        Assert.error("unknown type: should not happen");
609                }
610                return null;
611            }
612        }
613
614        StringBuilder getJvmSignature(Type type) {
615            Type t = types.erasure(type);
616            StringBuilder sig = new StringBuilder();
617            JvmTypeVisitor jv = new JvmTypeVisitor();
618            jv.visitType(t, sig);
619            return sig;
620        }
621    }
622
623    static class SimpleTypeVisitor<R, P> implements Type.Visitor<R, P> {
624
625        protected final R DEFAULT_VALUE;
626
627        protected SimpleTypeVisitor() {
628            DEFAULT_VALUE = null;
629        }
630
631        protected SimpleTypeVisitor(R defaultValue) {
632            DEFAULT_VALUE = defaultValue;
633        }
634
635        protected R defaultAction(Type t, P p) {
636            return DEFAULT_VALUE;
637        }
638
639        @Override
640        public R visitClassType(Type.ClassType t, P p) {
641            return defaultAction(t, p);
642        }
643
644        @Override
645        public R visitWildcardType(Type.WildcardType t, P p) {
646            return defaultAction(t, p);
647        }
648
649        @Override
650        public R visitArrayType(Type.ArrayType t, P p) {
651            return defaultAction(t, p);
652        }
653
654        @Override
655        public R visitMethodType(Type.MethodType t, P p) {
656            return defaultAction(t, p);
657        }
658
659        @Override
660        public R visitPackageType(Type.PackageType t, P p) {
661            return defaultAction(t, p);
662        }
663
664        @Override
665        public R visitTypeVar(Type.TypeVar t, P p) {
666            return defaultAction(t, p);
667        }
668
669        @Override
670        public R visitCapturedType(Type.CapturedType t, P p) {
671            return defaultAction(t, p);
672        }
673
674        @Override
675        public R visitForAll(Type.ForAll t, P p) {
676            return defaultAction(t, p);
677        }
678
679        @Override
680        public R visitUndetVar(Type.UndetVar t, P p) {
681            return defaultAction(t, p);
682        }
683
684        @Override
685        public R visitErrorType(Type.ErrorType t, P p) {
686            return defaultAction(t, p);
687        }
688
689        @Override
690        public R visitType(Type t, P p) {
691            return defaultAction(t, p);
692        }
693
694        @Override
695        public R visitModuleType(Type.ModuleType t, P p) {
696            return defaultAction(t, p);
697        }
698    }
699}
700