1 /*
   2  * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 
  27 package com.sun.tools.javah;
  28 
  29 import java.io.OutputStream;
  30 import java.io.PrintWriter;
  31 import java.util.ArrayList;
  32 import java.util.HashSet;
  33 import java.util.List;
  34 
  35 import java.util.Set;
  36 import javax.lang.model.element.Element;
  37 import javax.lang.model.element.ExecutableElement;
  38 import javax.lang.model.element.Modifier;
  39 import javax.lang.model.element.Name;
  40 import javax.lang.model.element.TypeElement;
  41 import javax.lang.model.element.VariableElement;
  42 import javax.lang.model.type.ArrayType;
  43 import javax.lang.model.type.PrimitiveType;
  44 import javax.lang.model.type.TypeKind;
  45 import javax.lang.model.type.TypeMirror;
  46 import javax.lang.model.type.TypeVisitor;
  47 import javax.lang.model.util.ElementFilter;
  48 import javax.lang.model.util.SimpleTypeVisitor6;
  49 
  50 /*
  51  * <p><b>This is NOT part of any API supported by Sun Microsystems.
  52  * If you write code that depends on this, you do so at your own
  53  * risk.  This code and its internal interfaces are subject to change
  54  * or deletion without notice.</b></p>
  55  *
  56  * @author  Sucheta Dambalkar(Revised)
  57  */
  58 public class LLNI extends Gen {
  59 
  60     protected final char  innerDelim = '$';     /* For inner classes */
  61     protected Set<String>  doneHandleTypes;
  62     List<VariableElement> fields;
  63     List<ExecutableElement> methods;
  64     private boolean       doubleAlign;
  65     private int           padFieldNum = 0;
  66 
  67     LLNI(boolean doubleAlign, Util util) {
  68         super(util);
  69         this.doubleAlign = doubleAlign;
  70     }
  71 
  72     protected String getIncludes() {
  73         return "";
  74     }
  75 
  76     protected void write(OutputStream o, TypeElement clazz) throws Util.Exit {
  77         String cname     = mangleClassName(clazz.getQualifiedName().toString());
  78         PrintWriter pw   = wrapWriter(o);
  79         fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
  80         methods = ElementFilter.methodsIn(clazz.getEnclosedElements());
  81         generateDeclsForClass(pw, clazz, cname);
  82         // FIXME check if errors occurred on the PrintWriter and throw exception if so
  83     }
  84 
  85     protected void generateDeclsForClass(PrintWriter pw,
  86             TypeElement clazz, String cname) throws Util.Exit {
  87         doneHandleTypes  = new HashSet<String>();
  88         /* The following handle types are predefined in "typedefs.h". Suppress
  89            inclusion in the output by generating them "into the blue" here. */
  90         genHandleType(null, "java.lang.Class");
  91         genHandleType(null, "java.lang.ClassLoader");
  92         genHandleType(null, "java.lang.Object");
  93         genHandleType(null, "java.lang.String");
  94         genHandleType(null, "java.lang.Thread");
  95         genHandleType(null, "java.lang.ThreadGroup");
  96         genHandleType(null, "java.lang.Throwable");
  97 
  98         pw.println("/* LLNI Header for class " + clazz.getQualifiedName() + " */" + lineSep);
  99         pw.println("#ifndef _Included_" + cname);
 100         pw.println("#define _Included_" + cname);
 101         pw.println("#include \"typedefs.h\"");
 102         pw.println("#include \"llni.h\"");
 103         pw.println("#include \"jni.h\"" + lineSep);
 104 
 105         forwardDecls(pw, clazz);
 106         structSectionForClass(pw, clazz, cname);
 107         methodSectionForClass(pw, clazz, cname);
 108         pw.println("#endif");
 109     }
 110 
 111     protected void genHandleType(PrintWriter pw, String clazzname) {
 112         String cname = mangleClassName(clazzname);
 113         if (!doneHandleTypes.contains(cname)) {
 114             doneHandleTypes.add(cname);
 115             if (pw != null) {
 116                 pw.println("#ifndef DEFINED_" + cname);
 117                 pw.println("    #define DEFINED_" + cname);
 118                 pw.println("    GEN_HANDLE_TYPES(" + cname + ");");
 119                 pw.println("#endif" + lineSep);
 120             }
 121         }
 122     }
 123 
 124     protected String mangleClassName(String s) {
 125         return s.replace('.', '_')
 126             .replace('/', '_')
 127             .replace(innerDelim, '_');
 128     }
 129 
 130     protected void forwardDecls(PrintWriter pw, TypeElement clazz) {
 131         TypeElement object = elems.getTypeElement("java.lang.Object");
 132         if (clazz.equals(object))
 133             return;
 134 
 135         genHandleType(pw, clazz.getQualifiedName().toString());
 136         TypeElement superClass = (TypeElement) (types.asElement(clazz.getSuperclass()));
 137 
 138         if (superClass != null) {
 139             String superClassName = superClass.getQualifiedName().toString();
 140             forwardDecls(pw, superClass);
 141         }
 142 
 143         for (VariableElement field: fields) {
 144 
 145             if (!field.getModifiers().contains(Modifier.STATIC)) {
 146                 TypeMirror t = types.erasure(field.asType());
 147                 TypeSignature newTypeSig = new TypeSignature(elems);
 148                 String tname = newTypeSig.qualifiedTypeName(t);
 149                 String sig = newTypeSig.getTypeSignature(tname);
 150 
 151                 if (sig.charAt(0) != '[')
 152                     forwardDeclsFromSig(pw, sig);
 153             }
 154         }
 155 
 156         for (ExecutableElement method: methods) {
 157 
 158             if (method.getModifiers().contains(Modifier.NATIVE)) {
 159                 TypeMirror retType = types.erasure(method.getReturnType());
 160                 String typesig = signature(method);
 161                 TypeSignature newTypeSig = new TypeSignature(elems);
 162                 String sig = newTypeSig.getTypeSignature(typesig, retType);
 163 
 164                 if (sig.charAt(0) != '[')
 165                     forwardDeclsFromSig(pw, sig);
 166 
 167             }
 168         }
 169     }
 170 
 171     protected void forwardDeclsFromSig(PrintWriter pw, String sig) {
 172         int    len = sig.length();
 173         int    i   = sig.charAt(0) == '(' ? 1 : 0;
 174 
 175         /* Skip the initial "(". */
 176         while (i < len) {
 177             if (sig.charAt(i) == 'L') {
 178                 int j = i + 1;
 179                 while (sig.charAt(j) != ';') j++;
 180                 genHandleType(pw, sig.substring(i + 1, j));
 181                 i = j + 1;
 182             } else {
 183                 i++;
 184             }
 185         }
 186     }
 187 
 188     protected void structSectionForClass(PrintWriter pw,
 189                                          TypeElement jclazz, String cname) {
 190 
 191         String jname = jclazz.getQualifiedName().toString();
 192 
 193         if (cname.equals("java_lang_Object")) {
 194             pw.println("/* struct java_lang_Object is defined in typedefs.h. */");
 195             pw.println();
 196             return;
 197         }
 198         pw.println("#if !defined(__i386)");
 199         pw.println("#pragma pack(4)");
 200         pw.println("#endif");
 201         pw.println();
 202         pw.println("struct " + cname + " {");
 203         pw.println("    ObjHeader h;");
 204         pw.print(fieldDefs(jclazz, cname));
 205 
 206         if (jname.equals("java.lang.Class"))
 207             pw.println("    Class *LLNI_mask(cClass);" +
 208                        "  /* Fake field; don't access (see oobj.h) */");
 209         pw.println("};" + lineSep + lineSep + "#pragma pack()");
 210         pw.println();
 211         return;
 212     }
 213 
 214     private static class FieldDefsRes {
 215         public String className;        /* Name of the current class. */
 216         public FieldDefsRes parent;
 217         public String s;
 218         public int byteSize;
 219         public boolean bottomMost;
 220         public boolean printedOne = false;
 221 
 222         FieldDefsRes(TypeElement clazz, FieldDefsRes parent, boolean bottomMost) {
 223             this.className = clazz.getQualifiedName().toString();
 224             this.parent = parent;
 225             this.bottomMost = bottomMost;
 226             int byteSize = 0;
 227             if (parent == null) this.s = "";
 228             else this.s = parent.s;
 229         }
 230     }
 231 
 232     /* Returns "true" iff added a field. */
 233     private boolean doField(FieldDefsRes res, VariableElement field,
 234                             String cname, boolean padWord) {
 235 
 236         String fieldDef = addStructMember(field, cname, padWord);
 237         if (fieldDef != null) {
 238             if (!res.printedOne) { /* add separator */
 239                 if (res.bottomMost) {
 240                     if (res.s.length() != 0)
 241                         res.s = res.s + "    /* local members: */" + lineSep;
 242                 } else {
 243                     res.s = res.s + "    /* inherited members from " +
 244                         res.className + ": */" + lineSep;
 245                 }
 246                 res.printedOne = true;
 247             }
 248             res.s = res.s + fieldDef;
 249             return true;
 250         }
 251 
 252         // Otherwise.
 253         return false;
 254     }
 255 
 256     private int doTwoWordFields(FieldDefsRes res, TypeElement clazz,
 257                                 int offset, String cname, boolean padWord) {
 258         boolean first = true;
 259         List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
 260 
 261         for (VariableElement field: fields) {
 262             TypeKind tk = field.asType().getKind();
 263             boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
 264             if (twoWords && doField(res, field, cname, first && padWord)) {
 265                 offset += 8; first = false;
 266             }
 267         }
 268         return offset;
 269     }
 270 
 271     String fieldDefs(TypeElement clazz, String cname) {
 272         FieldDefsRes res = fieldDefs(clazz, cname, true);
 273         return res.s;
 274     }
 275 
 276     FieldDefsRes fieldDefs(TypeElement clazz, String cname,
 277                                      boolean bottomMost){
 278         FieldDefsRes res;
 279         int offset;
 280         boolean didTwoWordFields = false;
 281 
 282         TypeElement superclazz = (TypeElement) types.asElement(clazz.getSuperclass());
 283 
 284         if (superclazz != null) {
 285             String supername = superclazz.getQualifiedName().toString();
 286             res = new FieldDefsRes(clazz,
 287                                    fieldDefs(superclazz, cname, false),
 288                                    bottomMost);
 289             offset = res.parent.byteSize;
 290         } else {
 291             res = new FieldDefsRes(clazz, null, bottomMost);
 292             offset = 0;
 293         }
 294 
 295         List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
 296 
 297         for (VariableElement field: fields) {
 298 
 299             if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {
 300                 offset = doTwoWordFields(res, clazz, offset, cname, false);
 301                 didTwoWordFields = true;
 302             }
 303 
 304             TypeKind tk = field.asType().getKind();
 305             boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
 306 
 307             if (!doubleAlign || !twoWords) {
 308                 if (doField(res, field, cname, false)) offset += 4;
 309             }
 310 
 311         }
 312 
 313         if (doubleAlign && !didTwoWordFields) {
 314             if ((offset % 8) != 0) offset += 4;
 315             offset = doTwoWordFields(res, clazz, offset, cname, true);
 316         }
 317 
 318         res.byteSize = offset;
 319         return res;
 320     }
 321 
 322     /* OVERRIDE: This method handles instance fields */
 323     protected String addStructMember(VariableElement member, String cname,
 324                                      boolean padWord) {
 325         String res = null;
 326 
 327         if (member.getModifiers().contains(Modifier.STATIC)) {
 328             res = addStaticStructMember(member, cname);
 329             //   if (res == null) /* JNI didn't handle it, print comment. */
 330             //  res = "    /* Inaccessible static: " + member + " */" + lineSep;
 331         } else {
 332             TypeMirror mt = types.erasure(member.asType());
 333             if (padWord) res = "    java_int padWord" + padFieldNum++ + ";" + lineSep;
 334             res = "    " + llniType(mt, false, false) + " " + llniFieldName(member);
 335             if (isLongOrDouble(mt)) res = res + "[2]";
 336             res = res + ";" + lineSep;
 337         }
 338         return res;
 339     }
 340 
 341     static private final boolean isWindows =
 342         System.getProperty("os.name").startsWith("Windows");
 343 
 344     /*
 345      * This method only handles static final fields.
 346      */
 347     protected String addStaticStructMember(VariableElement field, String cname) {
 348         String res = null;
 349         Object exp = null;
 350 
 351         if (!field.getModifiers().contains(Modifier.STATIC))
 352             return res;
 353         if (!field.getModifiers().contains(Modifier.FINAL))
 354             return res;
 355 
 356         exp = field.getConstantValue();
 357 
 358         if (exp != null) {
 359             /* Constant. */
 360 
 361             String     cn     = cname + "_" + field.getSimpleName();
 362             String     suffix = null;
 363             long           val = 0;
 364             /* Can only handle int, long, float, and double fields. */
 365             if (exp instanceof Byte
 366                 || exp instanceof Short
 367                 || exp instanceof Integer) {
 368                 suffix = "L";
 369                 val = ((Number)exp).intValue();
 370             }
 371             else if (exp instanceof Long) {
 372                 // Visual C++ supports the i64 suffix, not LL
 373                 suffix = isWindows ? "i64" : "LL";
 374                 val = ((Long)exp).longValue();
 375             }
 376             else if (exp instanceof Float)  suffix = "f";
 377             else if (exp instanceof Double) suffix = "";
 378             else if (exp instanceof Character) {
 379                 suffix = "L";
 380                 Character ch = (Character) exp;
 381                 val = ((int) ch) & 0xffff;
 382             }
 383             if (suffix != null) {
 384                 // Some compilers will generate a spurious warning
 385                 // for the integer constants for Integer.MIN_VALUE
 386                 // and Long.MIN_VALUE so we handle them specially.
 387                 if ((suffix.equals("L") && (val == Integer.MIN_VALUE)) ||
 388                     (suffix.equals("LL") && (val == Long.MIN_VALUE))) {
 389                     res = "    #undef  " + cn + lineSep
 390                         + "    #define " + cn
 391                         + " (" + (val + 1) + suffix + "-1)" + lineSep;
 392                 } else if (suffix.equals("L") || suffix.endsWith("LL")) {
 393                     res = "    #undef  " + cn + lineSep
 394                         + "    #define " + cn + " " + val + suffix + lineSep;
 395                 } else {
 396                     res = "    #undef  " + cn + lineSep
 397                         + "    #define " + cn + " " + exp + suffix + lineSep;
 398                 }
 399             }
 400         }
 401         return res;
 402     }
 403 
 404     protected void methodSectionForClass(PrintWriter pw,
 405             TypeElement clazz, String cname)
 406             throws Util.Exit {
 407         String methods = methodDecls(clazz, cname);
 408 
 409         if (methods.length() != 0) {
 410             pw.println("/* Native method declarations: */" + lineSep);
 411             pw.println("#ifdef __cplusplus");
 412             pw.println("extern \"C\" {");
 413             pw.println("#endif" + lineSep);
 414             pw.println(methods);
 415             pw.println("#ifdef __cplusplus");
 416             pw.println("}");
 417             pw.println("#endif");
 418         }
 419     }
 420 
 421     protected String methodDecls(TypeElement clazz, String cname) throws Util.Exit {
 422 
 423         String res = "";
 424         for (ExecutableElement method: methods) {
 425             if (method.getModifiers().contains(Modifier.NATIVE))
 426                 res = res + methodDecl(method, clazz, cname);
 427         }
 428         return res;
 429     }
 430 
 431     protected String methodDecl(ExecutableElement method,
 432                                 TypeElement clazz, String cname)
 433     throws Util.Exit {
 434         String res = null;
 435 
 436         TypeMirror retType = types.erasure(method.getReturnType());
 437         String typesig = signature(method);
 438         TypeSignature newTypeSig = new TypeSignature(elems);
 439         String sig = newTypeSig.getTypeSignature(typesig, retType);
 440         boolean longName = needLongName(method, clazz);
 441 
 442         if (sig.charAt(0) != '(')
 443             util.error("invalid.method.signature", sig);
 444 
 445 
 446         res = "JNIEXPORT " + jniType(retType) + " JNICALL" + lineSep + jniMethodName(method, cname, longName)
 447             + "(JNIEnv *, " + cRcvrDecl(method, cname);
 448         List<? extends VariableElement> params = method.getParameters();
 449         List<TypeMirror> argTypes = new ArrayList<TypeMirror>();
 450         for (VariableElement p: params){
 451             argTypes.add(types.erasure(p.asType()));
 452         }
 453 
 454         /* It would have been nice to include the argument names in the
 455            declaration, but there seems to be a bug in the "BinaryField"
 456            class, causing the getArguments() method to return "null" for
 457            most (non-constructor) methods. */
 458         for (TypeMirror argType: argTypes)
 459             res = res + ", " + jniType(argType);
 460         res = res + ");" + lineSep;
 461         return res;
 462     }
 463 
 464     protected final boolean needLongName(ExecutableElement method,
 465                                          TypeElement clazz) {
 466         Name methodName = method.getSimpleName();
 467         for (ExecutableElement memberMethod: methods) {
 468             if ((memberMethod != method) &&
 469                 memberMethod.getModifiers().contains(Modifier.NATIVE) &&
 470                     (methodName.equals(memberMethod.getSimpleName())))
 471                 return true;
 472         }
 473         return false;
 474     }
 475 
 476     protected final String jniMethodName(ExecutableElement method, String cname,
 477                                          boolean longName) {
 478         String res = "Java_" + cname + "_" + method.getSimpleName();
 479 
 480         if (longName) {
 481             TypeMirror mType =  types.erasure(method.getReturnType());
 482             List<? extends VariableElement> params = method.getParameters();
 483             List<TypeMirror> argTypes = new ArrayList<TypeMirror>();
 484             for (VariableElement param: params) {
 485                 argTypes.add(types.erasure(param.asType()));
 486             }
 487 
 488             res = res + "__";
 489             for (TypeMirror t: argTypes) {
 490                 String tname = t.toString();
 491                 TypeSignature newTypeSig = new TypeSignature(elems);
 492                 String sig = newTypeSig.getTypeSignature(tname);
 493                 res = res + nameToIdentifier(sig);
 494             }
 495         }
 496         return res;
 497     }
 498 
 499     // copied from JNI.java
 500     protected final String jniType(TypeMirror t) throws Util.Exit {
 501         TypeElement throwable = elems.getTypeElement("java.lang.Throwable");
 502         TypeElement jClass = elems.getTypeElement("java.lang.Class");
 503         TypeElement jString = elems.getTypeElement("java.lang.String");
 504         Element tclassDoc = types.asElement(t);
 505 
 506         switch (t.getKind()) {
 507             case ARRAY: {
 508                 TypeMirror ct = ((ArrayType) t).getComponentType();
 509                 switch (ct.getKind()) {
 510                     case BOOLEAN:  return "jbooleanArray";
 511                     case BYTE:     return "jbyteArray";
 512                     case CHAR:     return "jcharArray";
 513                     case SHORT:    return "jshortArray";
 514                     case INT:      return "jintArray";
 515                     case LONG:     return "jlongArray";
 516                     case FLOAT:    return "jfloatArray";
 517                     case DOUBLE:   return "jdoubleArray";
 518                     case ARRAY:
 519                     case DECLARED: return "jobjectArray";
 520                     default: throw new Error(ct.toString());
 521                 }
 522             }
 523 
 524             case VOID:     return "void";
 525             case BOOLEAN:  return "jboolean";
 526             case BYTE:     return "jbyte";
 527             case CHAR:     return "jchar";
 528             case SHORT:    return "jshort";
 529             case INT:      return "jint";
 530             case LONG:     return "jlong";
 531             case FLOAT:    return "jfloat";
 532             case DOUBLE:   return "jdouble";
 533 
 534             case DECLARED: {
 535                 if (tclassDoc.equals(jString))
 536                     return "jstring";
 537                 else if (types.isAssignable(t, throwable.asType()))
 538                     return "jthrowable";
 539                 else if (types.isAssignable(t, jClass.asType()))
 540                     return "jclass";
 541                 else
 542                     return "jobject";
 543             }
 544         }
 545 
 546         util.bug("jni.unknown.type");
 547         return null; /* dead code. */
 548     }
 549 
 550     protected String llniType(TypeMirror t, boolean handleize, boolean longDoubleOK) {
 551         String res = null;
 552 
 553         switch (t.getKind()) {
 554             case ARRAY: {
 555                 TypeMirror ct = ((ArrayType) t).getComponentType();
 556                 switch (ct.getKind()) {
 557                     case BOOLEAN:  res = "IArrayOfBoolean"; break;
 558                     case BYTE:     res = "IArrayOfByte";    break;
 559                     case CHAR:     res = "IArrayOfChar";    break;
 560                     case SHORT:    res = "IArrayOfShort";   break;
 561                     case INT:      res = "IArrayOfInt";     break;
 562                     case LONG:     res = "IArrayOfLong";    break;
 563                     case FLOAT:    res = "IArrayOfFloat";   break;
 564                     case DOUBLE:   res = "IArrayOfDouble";  break;
 565                     case ARRAY:
 566                     case DECLARED: res = "IArrayOfRef";     break;
 567                     default: throw new Error(ct.getKind() + " " + ct);
 568                 }
 569                 if (!handleize) res = "DEREFERENCED_" + res;
 570                 break;
 571             }
 572 
 573             case VOID:
 574                 res = "void";
 575                 break;
 576 
 577             case BOOLEAN:
 578             case BYTE:
 579             case CHAR:
 580             case SHORT:
 581             case INT:
 582                 res = "java_int" ;
 583                 break;
 584 
 585             case LONG:
 586                 res = longDoubleOK ? "java_long" : "val32 /* java_long */";
 587                 break;
 588 
 589             case FLOAT:
 590                 res =  "java_float";
 591                 break;
 592 
 593             case DOUBLE:
 594                 res = longDoubleOK ? "java_double" : "val32 /* java_double */";
 595                 break;
 596 
 597             case DECLARED:
 598                 TypeElement e  = (TypeElement) types.asElement(t);
 599                 res = "I" +  mangleClassName(e.getQualifiedName().toString());
 600                 if (!handleize) res = "DEREFERENCED_" + res;
 601                 break;
 602 
 603             default:
 604                 throw new Error(t.getKind() + " " + t); // FIXME
 605         }
 606 
 607         return res;
 608     }
 609 
 610     protected final String cRcvrDecl(Element field, String cname) {
 611         return (field.getModifiers().contains(Modifier.STATIC) ? "jclass" : "jobject");
 612     }
 613 
 614     protected String maskName(String s) {
 615         return "LLNI_mask(" + s + ")";
 616     }
 617 
 618     protected String llniFieldName(VariableElement field) {
 619         return maskName(field.getSimpleName().toString());
 620     }
 621 
 622     protected final boolean isLongOrDouble(TypeMirror t) {
 623         TypeVisitor<Boolean,Void> v = new SimpleTypeVisitor6<Boolean,Void>() {
 624             public Boolean defaultAction(TypeMirror t, Void p){
 625                 return false;
 626             }
 627             public Boolean visitArray(ArrayType t, Void p) {
 628                 return visit(t.getComponentType(), p);
 629             }
 630             public Boolean visitPrimitive(PrimitiveType t, Void p) {
 631                 TypeKind tk = t.getKind();
 632                 return (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
 633             }
 634         };
 635         return v.visit(t, null);
 636     }
 637 
 638     /* Do unicode to ansi C identifier conversion.
 639        %%% This may not be right, but should be called more often. */
 640     protected final String nameToIdentifier(String name) {
 641         int len = name.length();
 642         StringBuffer buf = new StringBuffer(len);
 643         for (int i = 0; i < len; i++) {
 644             char c = name.charAt(i);
 645             if (isASCIILetterOrDigit(c))
 646                 buf.append(c);
 647             else if (c == '/')
 648                 buf.append('_');
 649             else if (c == '.')
 650                 buf.append('_');
 651             else if (c == '_')
 652                 buf.append("_1");
 653             else if (c == ';')
 654                 buf.append("_2");
 655             else if (c == '[')
 656                 buf.append("_3");
 657             else
 658                 buf.append("_0" + ((int)c));
 659         }
 660         return new String(buf);
 661     }
 662 
 663     protected final boolean isASCIILetterOrDigit(char c) {
 664         if (((c >= 'A') && (c <= 'Z')) ||
 665             ((c >= 'a') && (c <= 'z')) ||
 666             ((c >= '0') && (c <= '9')))
 667             return true;
 668         else
 669             return false;
 670     }
 671 }
 672