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