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