LLNI.java revision 3170:dc017a37aac5
1190214Srpaulo/*
2190214Srpaulo * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
3190214Srpaulo * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4190214Srpaulo *
5190214Srpaulo * This code is free software; you can redistribute it and/or modify it
6190214Srpaulo * under the terms of the GNU General Public License version 2 only, as
7190214Srpaulo * published by the Free Software Foundation.  Oracle designates this
8190214Srpaulo * particular file as subject to the "Classpath" exception as provided
9190214Srpaulo * by Oracle in the LICENSE file that accompanied this code.
10190214Srpaulo *
11190214Srpaulo * This code is distributed in the hope that it will be useful, but WITHOUT
12190214Srpaulo * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13190214Srpaulo * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14190214Srpaulo * version 2 for more details (a copy is included in the LICENSE file that
15190214Srpaulo * accompanied this code).
16190214Srpaulo *
17190214Srpaulo * You should have received a copy of the GNU General Public License version
18190214Srpaulo * 2 along with this work; if not, write to the Free Software Foundation,
19190214Srpaulo * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20190214Srpaulo *
21190214Srpaulo * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22190214Srpaulo * or visit www.oracle.com if you need additional information or have any
23190214Srpaulo * questions.
24190214Srpaulo */
25190214Srpaulo
26190214Srpaulopackage com.sun.tools.javah;
27190214Srpaulo
28190214Srpauloimport java.io.OutputStream;
29190214Srpauloimport java.io.PrintWriter;
30190214Srpauloimport java.util.ArrayList;
31190214Srpauloimport java.util.HashSet;
32190214Srpauloimport java.util.List;
33190214Srpaulo
34190214Srpauloimport java.util.Set;
35190214Srpauloimport javax.lang.model.element.Element;
36190214Srpauloimport javax.lang.model.element.ExecutableElement;
37190214Srpauloimport javax.lang.model.element.Modifier;
38190214Srpauloimport javax.lang.model.element.Name;
39190214Srpauloimport javax.lang.model.element.TypeElement;
40190214Srpauloimport javax.lang.model.element.VariableElement;
41190214Srpauloimport javax.lang.model.type.ArrayType;
42190214Srpauloimport javax.lang.model.type.PrimitiveType;
43190214Srpauloimport javax.lang.model.type.TypeKind;
44190214Srpauloimport javax.lang.model.type.TypeMirror;
45190214Srpauloimport javax.lang.model.type.TypeVisitor;
46190214Srpauloimport javax.lang.model.util.ElementFilter;
47190214Srpauloimport javax.lang.model.util.SimpleTypeVisitor9;
48190214Srpaulo
49190214Srpauloimport com.sun.tools.javac.util.DefinedBy;
50190214Srpauloimport com.sun.tools.javac.util.DefinedBy.Api;
51190214Srpaulo
52190214Srpaulo/*
53190214Srpaulo * <p><b>This is NOT part of any supported API.
54190214Srpaulo * If you write code that depends on this, you do so at your own
55190214Srpaulo * risk.  This code and its internal interfaces are subject to change
56190214Srpaulo * or deletion without notice.</b></p>
57190214Srpaulo *
58190214Srpaulo * @author  Sucheta Dambalkar(Revised)
59190214Srpaulo */
60190214Srpaulopublic class LLNI extends Gen {
61190214Srpaulo
62190214Srpaulo    protected final char  innerDelim = '$';     /* For inner classes */
63190214Srpaulo    protected Set<String>  doneHandleTypes;
64190214Srpaulo    List<VariableElement> fields;
65190214Srpaulo    List<ExecutableElement> methods;
66190214Srpaulo    private boolean       doubleAlign;
67190214Srpaulo    private int           padFieldNum = 0;
68190214Srpaulo
69190214Srpaulo    LLNI(boolean doubleAlign, Util util) {
70190214Srpaulo        super(util);
71190214Srpaulo        this.doubleAlign = doubleAlign;
72190214Srpaulo    }
73190214Srpaulo
74190214Srpaulo    protected String getIncludes() {
75190214Srpaulo        return "";
76190214Srpaulo    }
77190214Srpaulo
78190214Srpaulo    protected void write(OutputStream o, TypeElement clazz) throws Util.Exit {
79190214Srpaulo        try {
80190214Srpaulo            String cname     = mangleClassName(clazz.getQualifiedName().toString());
81190214Srpaulo            PrintWriter pw   = wrapWriter(o);
82190214Srpaulo            fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
83190214Srpaulo            methods = ElementFilter.methodsIn(clazz.getEnclosedElements());
84190214Srpaulo            generateDeclsForClass(pw, clazz, cname);
85190214Srpaulo            // FIXME check if errors occurred on the PrintWriter and throw exception if so
86190214Srpaulo        } catch (TypeSignature.SignatureException e) {
87190214Srpaulo            util.error("llni.sigerror", e.getMessage());
88190214Srpaulo        }
89190214Srpaulo    }
90190214Srpaulo
91190214Srpaulo    protected void generateDeclsForClass(PrintWriter pw,
92190214Srpaulo            TypeElement clazz, String cname)
93190214Srpaulo            throws TypeSignature.SignatureException, Util.Exit {
94190214Srpaulo        doneHandleTypes  = new HashSet<>();
95190214Srpaulo        /* The following handle types are predefined in "typedefs.h". Suppress
96190214Srpaulo           inclusion in the output by generating them "into the blue" here. */
97190214Srpaulo        genHandleType(null, "java.lang.Class");
98190214Srpaulo        genHandleType(null, "java.lang.ClassLoader");
99190214Srpaulo        genHandleType(null, "java.lang.Object");
100190214Srpaulo        genHandleType(null, "java.lang.String");
101190214Srpaulo        genHandleType(null, "java.lang.Thread");
102190214Srpaulo        genHandleType(null, "java.lang.ThreadGroup");
103190214Srpaulo        genHandleType(null, "java.lang.Throwable");
104190214Srpaulo
105190214Srpaulo        pw.println("/* LLNI Header for class " + clazz.getQualifiedName() + " */" + lineSep);
106190214Srpaulo        pw.println("#ifndef _Included_" + cname);
107190214Srpaulo        pw.println("#define _Included_" + cname);
108190214Srpaulo        pw.println("#include \"typedefs.h\"");
109190214Srpaulo        pw.println("#include \"llni.h\"");
110190214Srpaulo        pw.println("#include \"jni.h\"" + lineSep);
111190214Srpaulo
112190214Srpaulo        forwardDecls(pw, clazz);
113190214Srpaulo        structSectionForClass(pw, clazz, cname);
114190214Srpaulo        methodSectionForClass(pw, clazz, cname);
115190214Srpaulo        pw.println("#endif");
116190214Srpaulo    }
117190214Srpaulo
118190214Srpaulo    protected void genHandleType(PrintWriter pw, String clazzname) {
119190214Srpaulo        String cname = mangleClassName(clazzname);
120190214Srpaulo        if (!doneHandleTypes.contains(cname)) {
121190214Srpaulo            doneHandleTypes.add(cname);
122190214Srpaulo            if (pw != null) {
123190214Srpaulo                pw.println("#ifndef DEFINED_" + cname);
124190214Srpaulo                pw.println("    #define DEFINED_" + cname);
125190214Srpaulo                pw.println("    GEN_HANDLE_TYPES(" + cname + ");");
126190214Srpaulo                pw.println("#endif" + lineSep);
127190214Srpaulo            }
128190214Srpaulo        }
129190214Srpaulo    }
130190214Srpaulo
131190214Srpaulo    protected String mangleClassName(String s) {
132190214Srpaulo        return s.replace('.', '_')
133190214Srpaulo            .replace('/', '_')
134190214Srpaulo            .replace(innerDelim, '_');
135190214Srpaulo    }
136190214Srpaulo
137190214Srpaulo    protected void forwardDecls(PrintWriter pw, TypeElement clazz)
138190214Srpaulo            throws TypeSignature.SignatureException {
139190214Srpaulo        TypeElement object = elems.getTypeElement("java.lang.Object");
140190214Srpaulo        if (clazz.equals(object))
141190214Srpaulo            return;
142190214Srpaulo
143190214Srpaulo        genHandleType(pw, clazz.getQualifiedName().toString());
144190214Srpaulo        TypeElement superClass = (TypeElement) (types.asElement(clazz.getSuperclass()));
145190214Srpaulo
146190214Srpaulo        if (superClass != null) {
147190214Srpaulo            String superClassName = superClass.getQualifiedName().toString();
148190214Srpaulo            forwardDecls(pw, superClass);
149190214Srpaulo        }
150190214Srpaulo
151190214Srpaulo        for (VariableElement field: fields) {
152190214Srpaulo
153190214Srpaulo            if (!field.getModifiers().contains(Modifier.STATIC)) {
154190214Srpaulo                TypeMirror t = types.erasure(field.asType());
155190214Srpaulo                TypeSignature newTypeSig = new TypeSignature(elems);
156190214Srpaulo                String tname = newTypeSig.qualifiedTypeName(t);
157190214Srpaulo                String sig = newTypeSig.getTypeSignature(tname);
158190214Srpaulo
159190214Srpaulo                if (sig.charAt(0) != '[')
160190214Srpaulo                    forwardDeclsFromSig(pw, sig);
161190214Srpaulo            }
162190214Srpaulo        }
163190214Srpaulo
164190214Srpaulo        for (ExecutableElement method: methods) {
165190214Srpaulo
166190214Srpaulo            if (method.getModifiers().contains(Modifier.NATIVE)) {
167190214Srpaulo                TypeMirror retType = types.erasure(method.getReturnType());
168190214Srpaulo                String typesig = signature(method);
169190214Srpaulo                TypeSignature newTypeSig = new TypeSignature(elems);
170190214Srpaulo                String sig = newTypeSig.getTypeSignature(typesig, retType);
171190214Srpaulo
172190214Srpaulo                if (sig.charAt(0) != '[')
173190214Srpaulo                    forwardDeclsFromSig(pw, sig);
174190214Srpaulo
175190214Srpaulo            }
176190214Srpaulo        }
177190214Srpaulo    }
178190214Srpaulo
179190214Srpaulo    protected void forwardDeclsFromSig(PrintWriter pw, String sig) {
180190214Srpaulo        int    len = sig.length();
181190214Srpaulo        int    i   = sig.charAt(0) == '(' ? 1 : 0;
182190214Srpaulo
183190214Srpaulo        /* Skip the initial "(". */
184190214Srpaulo        while (i < len) {
185190214Srpaulo            if (sig.charAt(i) == 'L') {
186190214Srpaulo                int j = i + 1;
187190214Srpaulo                while (sig.charAt(j) != ';') j++;
188190214Srpaulo                genHandleType(pw, sig.substring(i + 1, j));
189190214Srpaulo                i = j + 1;
190190214Srpaulo            } else {
191190214Srpaulo                i++;
192190214Srpaulo            }
193190214Srpaulo        }
194190214Srpaulo    }
195190214Srpaulo
196190214Srpaulo    protected void structSectionForClass(PrintWriter pw,
197190214Srpaulo                                         TypeElement jclazz, String cname) {
198190214Srpaulo
199190214Srpaulo        String jname = jclazz.getQualifiedName().toString();
200190214Srpaulo
201190214Srpaulo        if (cname.equals("java_lang_Object")) {
202190214Srpaulo            pw.println("/* struct java_lang_Object is defined in typedefs.h. */");
203190214Srpaulo            pw.println();
204190214Srpaulo            return;
205190214Srpaulo        }
206190214Srpaulo        pw.println("#if !defined(__i386)");
207190214Srpaulo        pw.println("#pragma pack(4)");
208190214Srpaulo        pw.println("#endif");
209190214Srpaulo        pw.println();
210190214Srpaulo        pw.println("struct " + cname + " {");
211190214Srpaulo        pw.println("    ObjHeader h;");
212190214Srpaulo        pw.print(fieldDefs(jclazz, cname));
213190214Srpaulo
214190214Srpaulo        if (jname.equals("java.lang.Class"))
215190214Srpaulo            pw.println("    Class *LLNI_mask(cClass);" +
216190214Srpaulo                       "  /* Fake field; don't access (see oobj.h) */");
217190214Srpaulo        pw.println("};" + lineSep + lineSep + "#pragma pack()");
218190214Srpaulo        pw.println();
219190214Srpaulo        return;
220190214Srpaulo    }
221190214Srpaulo
222190214Srpaulo    private static class FieldDefsRes {
223190214Srpaulo        public String className;        /* Name of the current class. */
224190214Srpaulo        public FieldDefsRes parent;
225190214Srpaulo        public String s;
226190214Srpaulo        public int byteSize;
227190214Srpaulo        public boolean bottomMost;
228190214Srpaulo        public boolean printedOne = false;
229190214Srpaulo
230190214Srpaulo        FieldDefsRes(TypeElement clazz, FieldDefsRes parent, boolean bottomMost) {
231190214Srpaulo            this.className = clazz.getQualifiedName().toString();
232190214Srpaulo            this.parent = parent;
233190214Srpaulo            this.bottomMost = bottomMost;
234190214Srpaulo            int byteSize = 0;
235190214Srpaulo            if (parent == null) this.s = "";
236190214Srpaulo            else this.s = parent.s;
237190214Srpaulo        }
238190214Srpaulo    }
239190214Srpaulo
240190214Srpaulo    /* Returns "true" iff added a field. */
241190214Srpaulo    private boolean doField(FieldDefsRes res, VariableElement field,
242190214Srpaulo                            String cname, boolean padWord) {
243190214Srpaulo
244190214Srpaulo        String fieldDef = addStructMember(field, cname, padWord);
245190214Srpaulo        if (fieldDef != null) {
246190214Srpaulo            if (!res.printedOne) { /* add separator */
247190214Srpaulo                if (res.bottomMost) {
248190214Srpaulo                    if (res.s.length() != 0)
249190214Srpaulo                        res.s = res.s + "    /* local members: */" + lineSep;
250190214Srpaulo                } else {
251190214Srpaulo                    res.s = res.s + "    /* inherited members from " +
252190214Srpaulo                        res.className + ": */" + lineSep;
253190214Srpaulo                }
254190214Srpaulo                res.printedOne = true;
255190214Srpaulo            }
256190214Srpaulo            res.s = res.s + fieldDef;
257190214Srpaulo            return true;
258190214Srpaulo        }
259190214Srpaulo
260190214Srpaulo        // Otherwise.
261190214Srpaulo        return false;
262190214Srpaulo    }
263190214Srpaulo
264190214Srpaulo    private int doTwoWordFields(FieldDefsRes res, TypeElement clazz,
265190214Srpaulo                                int offset, String cname, boolean padWord) {
266190214Srpaulo        boolean first = true;
267190214Srpaulo        List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
268190214Srpaulo
269190214Srpaulo        for (VariableElement field: fields) {
270190214Srpaulo            TypeKind tk = field.asType().getKind();
271190214Srpaulo            boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
272190214Srpaulo            if (twoWords && doField(res, field, cname, first && padWord)) {
273190214Srpaulo                offset += 8; first = false;
274190214Srpaulo            }
275190214Srpaulo        }
276190214Srpaulo        return offset;
277190214Srpaulo    }
278190214Srpaulo
279190214Srpaulo    String fieldDefs(TypeElement clazz, String cname) {
280190214Srpaulo        FieldDefsRes res = fieldDefs(clazz, cname, true);
281190214Srpaulo        return res.s;
282190214Srpaulo    }
283190214Srpaulo
284190214Srpaulo    FieldDefsRes fieldDefs(TypeElement clazz, String cname,
285190214Srpaulo                                     boolean bottomMost){
286190214Srpaulo        FieldDefsRes res;
287190214Srpaulo        int offset;
288190214Srpaulo        boolean didTwoWordFields = false;
289190214Srpaulo
290190214Srpaulo        TypeElement superclazz = (TypeElement) types.asElement(clazz.getSuperclass());
291190214Srpaulo
292190214Srpaulo        if (superclazz != null) {
293190214Srpaulo            String supername = superclazz.getQualifiedName().toString();
294190214Srpaulo            res = new FieldDefsRes(clazz,
295190214Srpaulo                                   fieldDefs(superclazz, cname, false),
296190214Srpaulo                                   bottomMost);
297190214Srpaulo            offset = res.parent.byteSize;
298190214Srpaulo        } else {
299190214Srpaulo            res = new FieldDefsRes(clazz, null, bottomMost);
300190214Srpaulo            offset = 0;
301190214Srpaulo        }
302190214Srpaulo
303190214Srpaulo        List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
304190214Srpaulo
305190214Srpaulo        for (VariableElement field: fields) {
306190214Srpaulo
307190214Srpaulo            if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {
308190214Srpaulo                offset = doTwoWordFields(res, clazz, offset, cname, false);
309190214Srpaulo                didTwoWordFields = true;
310190214Srpaulo            }
311190214Srpaulo
312190214Srpaulo            TypeKind tk = field.asType().getKind();
313190214Srpaulo            boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
314190214Srpaulo
315190214Srpaulo            if (!doubleAlign || !twoWords) {
316190214Srpaulo                if (doField(res, field, cname, false)) offset += 4;
317190214Srpaulo            }
318190214Srpaulo
319190214Srpaulo        }
320190214Srpaulo
321190214Srpaulo        if (doubleAlign && !didTwoWordFields) {
322190214Srpaulo            if ((offset % 8) != 0) offset += 4;
323190214Srpaulo            offset = doTwoWordFields(res, clazz, offset, cname, true);
324190214Srpaulo        }
325190214Srpaulo
326190214Srpaulo        res.byteSize = offset;
327190214Srpaulo        return res;
328190214Srpaulo    }
329190214Srpaulo
330190214Srpaulo    /* OVERRIDE: This method handles instance fields */
331190214Srpaulo    protected String addStructMember(VariableElement member, String cname,
332190214Srpaulo                                     boolean padWord) {
333190214Srpaulo        String res = null;
334190214Srpaulo
335190214Srpaulo        if (member.getModifiers().contains(Modifier.STATIC)) {
336190214Srpaulo            res = addStaticStructMember(member, cname);
337190214Srpaulo            //   if (res == null) /* JNI didn't handle it, print comment. */
338190214Srpaulo            //  res = "    /* Inaccessible static: " + member + " */" + lineSep;
339190214Srpaulo        } else {
340190214Srpaulo            TypeMirror mt = types.erasure(member.asType());
341190214Srpaulo            if (padWord) res = "    java_int padWord" + padFieldNum++ + ";" + lineSep;
342190214Srpaulo            res = "    " + llniType(mt, false, false) + " " + llniFieldName(member);
343190214Srpaulo            if (isLongOrDouble(mt)) res = res + "[2]";
344190214Srpaulo            res = res + ";" + lineSep;
345190214Srpaulo        }
346190214Srpaulo        return res;
347190214Srpaulo    }
348190214Srpaulo
349190214Srpaulo    static private final boolean isWindows =
350190214Srpaulo        System.getProperty("os.name").startsWith("Windows");
351190214Srpaulo
352190214Srpaulo    /*
353190214Srpaulo     * This method only handles static final fields.
354190214Srpaulo     */
355190214Srpaulo    protected String addStaticStructMember(VariableElement field, String cname) {
356190214Srpaulo        String res = null;
357190214Srpaulo        Object exp = null;
358190214Srpaulo
359190214Srpaulo        if (!field.getModifiers().contains(Modifier.STATIC))
360190214Srpaulo            return res;
361190214Srpaulo        if (!field.getModifiers().contains(Modifier.FINAL))
362190214Srpaulo            return res;
363190214Srpaulo
364190214Srpaulo        exp = field.getConstantValue();
365190214Srpaulo
366190214Srpaulo        if (exp != null) {
367190214Srpaulo            /* Constant. */
368190214Srpaulo
369190214Srpaulo            String     cn     = cname + "_" + field.getSimpleName();
370190214Srpaulo            String     suffix = null;
371190214Srpaulo            long           val = 0;
372190214Srpaulo            /* Can only handle int, long, float, and double fields. */
373190214Srpaulo            if (exp instanceof Byte
374190214Srpaulo                || exp instanceof Short
375190214Srpaulo                || exp instanceof Integer) {
376190214Srpaulo                suffix = "L";
377190214Srpaulo                val = ((Number)exp).intValue();
378190214Srpaulo            }
379190214Srpaulo            else if (exp instanceof Long) {
380190214Srpaulo                // Visual C++ supports the i64 suffix, not LL
381190214Srpaulo                suffix = isWindows ? "i64" : "LL";
382190214Srpaulo                val = ((Long)exp).longValue();
383190214Srpaulo            }
384190214Srpaulo            else if (exp instanceof Float)  suffix = "f";
385190214Srpaulo            else if (exp instanceof Double) suffix = "";
386190214Srpaulo            else if (exp instanceof Character) {
387190214Srpaulo                suffix = "L";
388190214Srpaulo                Character ch = (Character) exp;
389190214Srpaulo                val = ((int) ch) & 0xffff;
390190214Srpaulo            }
391190214Srpaulo            if (suffix != null) {
392190214Srpaulo                // Some compilers will generate a spurious warning
393190214Srpaulo                // for the integer constants for Integer.MIN_VALUE
394190214Srpaulo                // and Long.MIN_VALUE so we handle them specially.
395190214Srpaulo                if ((suffix.equals("L") && (val == Integer.MIN_VALUE)) ||
396190214Srpaulo                    (suffix.equals("LL") && (val == Long.MIN_VALUE))) {
397190214Srpaulo                    res = "    #undef  " + cn + lineSep
398190214Srpaulo                        + "    #define " + cn
399190214Srpaulo                        + " (" + (val + 1) + suffix + "-1)" + lineSep;
400190214Srpaulo                } else if (suffix.equals("L") || suffix.endsWith("LL")) {
401190214Srpaulo                    res = "    #undef  " + cn + lineSep
402190214Srpaulo                        + "    #define " + cn + " " + val + suffix + lineSep;
403190214Srpaulo                } else {
404190214Srpaulo                    res = "    #undef  " + cn + lineSep
405190214Srpaulo                        + "    #define " + cn + " " + exp + suffix + lineSep;
406190214Srpaulo                }
407190214Srpaulo            }
408190214Srpaulo        }
409190214Srpaulo        return res;
410190214Srpaulo    }
411190214Srpaulo
412190214Srpaulo    protected void methodSectionForClass(PrintWriter pw,
413190214Srpaulo            TypeElement clazz, String cname)
414190214Srpaulo            throws TypeSignature.SignatureException, Util.Exit {
415190214Srpaulo        String methods = methodDecls(clazz, cname);
416190214Srpaulo
417190214Srpaulo        if (methods.length() != 0) {
418190214Srpaulo            pw.println("/* Native method declarations: */" + lineSep);
419190214Srpaulo            pw.println("#ifdef __cplusplus");
420190214Srpaulo            pw.println("extern \"C\" {");
421190214Srpaulo            pw.println("#endif" + lineSep);
422190214Srpaulo            pw.println(methods);
423190214Srpaulo            pw.println("#ifdef __cplusplus");
424190214Srpaulo            pw.println("}");
425190214Srpaulo            pw.println("#endif");
426190214Srpaulo        }
427190214Srpaulo    }
428190214Srpaulo
429190214Srpaulo    protected String methodDecls(TypeElement clazz, String cname)
430190214Srpaulo            throws TypeSignature.SignatureException, Util.Exit {
431190214Srpaulo
432190214Srpaulo        String res = "";
433190214Srpaulo        for (ExecutableElement method: methods) {
434190214Srpaulo            if (method.getModifiers().contains(Modifier.NATIVE))
435190214Srpaulo                res = res + methodDecl(method, clazz, cname);
436190214Srpaulo        }
437190214Srpaulo        return res;
438190214Srpaulo    }
439190214Srpaulo
440190214Srpaulo    protected String methodDecl(ExecutableElement method,
441190214Srpaulo                                TypeElement clazz, String cname)
442190214Srpaulo            throws TypeSignature.SignatureException, Util.Exit {
443190214Srpaulo        String res = null;
444190214Srpaulo
445190214Srpaulo        TypeMirror retType = types.erasure(method.getReturnType());
446190214Srpaulo        String typesig = signature(method);
447190214Srpaulo        TypeSignature newTypeSig = new TypeSignature(elems);
448190214Srpaulo        String sig = newTypeSig.getTypeSignature(typesig, retType);
449190214Srpaulo        boolean longName = needLongName(method, clazz);
450190214Srpaulo
451190214Srpaulo        if (sig.charAt(0) != '(')
452190214Srpaulo            util.error("invalid.method.signature", sig);
453190214Srpaulo
454190214Srpaulo
455190214Srpaulo        res = "JNIEXPORT " + jniType(retType) + " JNICALL" + lineSep + jniMethodName(method, cname, longName)
456190214Srpaulo            + "(JNIEnv *, " + cRcvrDecl(method, cname);
457190214Srpaulo        List<? extends VariableElement> params = method.getParameters();
458190214Srpaulo        List<TypeMirror> argTypes = new ArrayList<>();
459190214Srpaulo        for (VariableElement p: params){
460190214Srpaulo            argTypes.add(types.erasure(p.asType()));
461190214Srpaulo        }
462190214Srpaulo
463190214Srpaulo        /* It would have been nice to include the argument names in the
464190214Srpaulo           declaration, but there seems to be a bug in the "BinaryField"
465190214Srpaulo           class, causing the getArguments() method to return "null" for
466190214Srpaulo           most (non-constructor) methods. */
467190214Srpaulo        for (TypeMirror argType: argTypes)
468190214Srpaulo            res = res + ", " + jniType(argType);
469190214Srpaulo        res = res + ");" + lineSep;
470190214Srpaulo        return res;
471190214Srpaulo    }
472190214Srpaulo
473190214Srpaulo    protected final boolean needLongName(ExecutableElement method,
474190214Srpaulo                                         TypeElement clazz) {
475190214Srpaulo        Name methodName = method.getSimpleName();
476190214Srpaulo        for (ExecutableElement memberMethod: methods) {
477190214Srpaulo            if ((memberMethod != method) &&
478190214Srpaulo                memberMethod.getModifiers().contains(Modifier.NATIVE) &&
479190214Srpaulo                    (methodName.equals(memberMethod.getSimpleName())))
480190214Srpaulo                return true;
481190214Srpaulo        }
482190214Srpaulo        return false;
483190214Srpaulo    }
484190214Srpaulo
485190214Srpaulo    protected final String jniMethodName(ExecutableElement method, String cname,
486190214Srpaulo                                         boolean longName)
487190214Srpaulo                throws TypeSignature.SignatureException {
488190214Srpaulo        String res = "Java_" + cname + "_" + method.getSimpleName();
489190214Srpaulo
490190214Srpaulo        if (longName) {
491190214Srpaulo            TypeMirror mType =  types.erasure(method.getReturnType());
492190214Srpaulo            List<? extends VariableElement> params = method.getParameters();
493190214Srpaulo            List<TypeMirror> argTypes = new ArrayList<>();
494190214Srpaulo            for (VariableElement param: params) {
495190214Srpaulo                argTypes.add(types.erasure(param.asType()));
496190214Srpaulo            }
497190214Srpaulo
498190214Srpaulo            res = res + "__";
499190214Srpaulo            for (TypeMirror t: argTypes) {
500190214Srpaulo                String tname = t.toString();
501190214Srpaulo                TypeSignature newTypeSig = new TypeSignature(elems);
502190214Srpaulo                String sig = newTypeSig.getTypeSignature(tname);
503190214Srpaulo                res = res + nameToIdentifier(sig);
504190214Srpaulo            }
505190214Srpaulo        }
506190214Srpaulo        return res;
507190214Srpaulo    }
508190214Srpaulo
509190214Srpaulo    // copied from JNI.java
510190214Srpaulo    protected final String jniType(TypeMirror t) throws Util.Exit {
511190214Srpaulo        TypeElement throwable = elems.getTypeElement("java.lang.Throwable");
512190214Srpaulo        TypeElement jClass = elems.getTypeElement("java.lang.Class");
513190214Srpaulo        TypeElement jString = elems.getTypeElement("java.lang.String");
514190214Srpaulo        Element tclassDoc = types.asElement(t);
515190214Srpaulo
516190214Srpaulo        switch (t.getKind()) {
517190214Srpaulo            case ARRAY: {
518190214Srpaulo                TypeMirror ct = ((ArrayType) t).getComponentType();
519190214Srpaulo                switch (ct.getKind()) {
520190214Srpaulo                    case BOOLEAN:  return "jbooleanArray";
521190214Srpaulo                    case BYTE:     return "jbyteArray";
522190214Srpaulo                    case CHAR:     return "jcharArray";
523190214Srpaulo                    case SHORT:    return "jshortArray";
524190214Srpaulo                    case INT:      return "jintArray";
525190214Srpaulo                    case LONG:     return "jlongArray";
526190214Srpaulo                    case FLOAT:    return "jfloatArray";
527190214Srpaulo                    case DOUBLE:   return "jdoubleArray";
528190214Srpaulo                    case ARRAY:
529190214Srpaulo                    case DECLARED: return "jobjectArray";
530190214Srpaulo                    default: throw new Error(ct.toString());
531190214Srpaulo                }
532190214Srpaulo            }
533190214Srpaulo
534190214Srpaulo            case VOID:     return "void";
535190214Srpaulo            case BOOLEAN:  return "jboolean";
536190214Srpaulo            case BYTE:     return "jbyte";
537190214Srpaulo            case CHAR:     return "jchar";
538190214Srpaulo            case SHORT:    return "jshort";
539190214Srpaulo            case INT:      return "jint";
540190214Srpaulo            case LONG:     return "jlong";
541190214Srpaulo            case FLOAT:    return "jfloat";
542190214Srpaulo            case DOUBLE:   return "jdouble";
543190214Srpaulo
544190214Srpaulo            case DECLARED: {
545190214Srpaulo                if (tclassDoc.equals(jString))
546190214Srpaulo                    return "jstring";
547190214Srpaulo                else if (types.isAssignable(t, throwable.asType()))
548190214Srpaulo                    return "jthrowable";
549190214Srpaulo                else if (types.isAssignable(t, jClass.asType()))
550190214Srpaulo                    return "jclass";
551190214Srpaulo                else
552190214Srpaulo                    return "jobject";
553190214Srpaulo            }
554190214Srpaulo        }
555190214Srpaulo
556190214Srpaulo        util.bug("jni.unknown.type");
557190214Srpaulo        return null; /* dead code. */
558190214Srpaulo    }
559190214Srpaulo
560190214Srpaulo    protected String llniType(TypeMirror t, boolean handleize, boolean longDoubleOK) {
561190214Srpaulo        String res = null;
562190214Srpaulo
563190214Srpaulo        switch (t.getKind()) {
564190214Srpaulo            case ARRAY: {
565190214Srpaulo                TypeMirror ct = ((ArrayType) t).getComponentType();
566190214Srpaulo                switch (ct.getKind()) {
567190214Srpaulo                    case BOOLEAN:  res = "IArrayOfBoolean"; break;
568190214Srpaulo                    case BYTE:     res = "IArrayOfByte";    break;
569190214Srpaulo                    case CHAR:     res = "IArrayOfChar";    break;
570190214Srpaulo                    case SHORT:    res = "IArrayOfShort";   break;
571190214Srpaulo                    case INT:      res = "IArrayOfInt";     break;
572190214Srpaulo                    case LONG:     res = "IArrayOfLong";    break;
573190214Srpaulo                    case FLOAT:    res = "IArrayOfFloat";   break;
574190214Srpaulo                    case DOUBLE:   res = "IArrayOfDouble";  break;
575190214Srpaulo                    case ARRAY:
576190214Srpaulo                    case DECLARED: res = "IArrayOfRef";     break;
577190214Srpaulo                    default: throw new Error(ct.getKind() + " " + ct);
578190214Srpaulo                }
579190214Srpaulo                if (!handleize) res = "DEREFERENCED_" + res;
580190214Srpaulo                break;
581190214Srpaulo            }
582190214Srpaulo
583190214Srpaulo            case VOID:
584190214Srpaulo                res = "void";
585190214Srpaulo                break;
586190214Srpaulo
587190214Srpaulo            case BOOLEAN:
588190214Srpaulo            case BYTE:
589190214Srpaulo            case CHAR:
590190214Srpaulo            case SHORT:
591190214Srpaulo            case INT:
592190214Srpaulo                res = "java_int" ;
593190214Srpaulo                break;
594190214Srpaulo
595190214Srpaulo            case LONG:
596190214Srpaulo                res = longDoubleOK ? "java_long" : "val32 /* java_long */";
597190214Srpaulo                break;
598190214Srpaulo
599190214Srpaulo            case FLOAT:
600190214Srpaulo                res =  "java_float";
601190214Srpaulo                break;
602190214Srpaulo
603190214Srpaulo            case DOUBLE:
604190214Srpaulo                res = longDoubleOK ? "java_double" : "val32 /* java_double */";
605190214Srpaulo                break;
606190214Srpaulo
607190214Srpaulo            case DECLARED:
608190214Srpaulo                TypeElement e  = (TypeElement) types.asElement(t);
609190214Srpaulo                res = "I" +  mangleClassName(e.getQualifiedName().toString());
610190214Srpaulo                if (!handleize) res = "DEREFERENCED_" + res;
611190214Srpaulo                break;
612190214Srpaulo
613190214Srpaulo            default:
614190214Srpaulo                throw new Error(t.getKind() + " " + t); // FIXME
615190214Srpaulo        }
616190214Srpaulo
617190214Srpaulo        return res;
618190214Srpaulo    }
619190214Srpaulo
620190214Srpaulo    protected final String cRcvrDecl(Element field, String cname) {
621190214Srpaulo        return (field.getModifiers().contains(Modifier.STATIC) ? "jclass" : "jobject");
622190214Srpaulo    }
623190214Srpaulo
624190214Srpaulo    protected String maskName(String s) {
625190214Srpaulo        return "LLNI_mask(" + s + ")";
626    }
627
628    protected String llniFieldName(VariableElement field) {
629        return maskName(field.getSimpleName().toString());
630    }
631
632    protected final boolean isLongOrDouble(TypeMirror t) {
633        TypeVisitor<Boolean,Void> v = new SimpleTypeVisitor9<Boolean,Void>() {
634            @DefinedBy(Api.LANGUAGE_MODEL)
635            public Boolean defaultAction(TypeMirror t, Void p){
636                return false;
637            }
638            @DefinedBy(Api.LANGUAGE_MODEL)
639            public Boolean visitArray(ArrayType t, Void p) {
640                return visit(t.getComponentType(), p);
641            }
642            @DefinedBy(Api.LANGUAGE_MODEL)
643            public Boolean visitPrimitive(PrimitiveType t, Void p) {
644                TypeKind tk = t.getKind();
645                return (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
646            }
647        };
648        return v.visit(t, null);
649    }
650
651    /* Do unicode to ansi C identifier conversion.
652       %%% This may not be right, but should be called more often. */
653    protected final String nameToIdentifier(String name) {
654        int len = name.length();
655        StringBuilder buf = new StringBuilder(len);
656        for (int i = 0; i < len; i++) {
657            char c = name.charAt(i);
658            if (isASCIILetterOrDigit(c))
659                buf.append(c);
660            else if (c == '/')
661                buf.append('_');
662            else if (c == '.')
663                buf.append('_');
664            else if (c == '_')
665                buf.append("_1");
666            else if (c == ';')
667                buf.append("_2");
668            else if (c == '[')
669                buf.append("_3");
670            else
671                buf.append("_0" + ((int)c));
672        }
673        return new String(buf);
674    }
675
676    protected final boolean isASCIILetterOrDigit(char c) {
677        if (((c >= 'A') && (c <= 'Z')) ||
678            ((c >= 'a') && (c <= 'z')) ||
679            ((c >= '0') && (c <= '9')))
680            return true;
681        else
682            return false;
683    }
684}
685
686