Thu, 10 Jun 2010 16:08:01 -0700
6944312: Potential rebranding issues in openjdk/langtools repository sources
Reviewed-by: darcy
1 /*
2 * Copyright (c) 2002, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
27 package com.sun.tools.javah;
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;
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.SimpleTypeVisitor7;
50 /*
51 * <p><b>This is NOT part of any supported API.
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 {
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;
67 LLNI(boolean doubleAlign, Util util) {
68 super(util);
69 this.doubleAlign = doubleAlign;
70 }
72 protected String getIncludes() {
73 return "";
74 }
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 }
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");
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);
105 forwardDecls(pw, clazz);
106 structSectionForClass(pw, clazz, cname);
107 methodSectionForClass(pw, clazz, cname);
108 pw.println("#endif");
109 }
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 }
124 protected String mangleClassName(String s) {
125 return s.replace('.', '_')
126 .replace('/', '_')
127 .replace(innerDelim, '_');
128 }
130 protected void forwardDecls(PrintWriter pw, TypeElement clazz) {
131 TypeElement object = elems.getTypeElement("java.lang.Object");
132 if (clazz.equals(object))
133 return;
135 genHandleType(pw, clazz.getQualifiedName().toString());
136 TypeElement superClass = (TypeElement) (types.asElement(clazz.getSuperclass()));
138 if (superClass != null) {
139 String superClassName = superClass.getQualifiedName().toString();
140 forwardDecls(pw, superClass);
141 }
143 for (VariableElement field: fields) {
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);
151 if (sig.charAt(0) != '[')
152 forwardDeclsFromSig(pw, sig);
153 }
154 }
156 for (ExecutableElement method: methods) {
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);
164 if (sig.charAt(0) != '[')
165 forwardDeclsFromSig(pw, sig);
167 }
168 }
169 }
171 protected void forwardDeclsFromSig(PrintWriter pw, String sig) {
172 int len = sig.length();
173 int i = sig.charAt(0) == '(' ? 1 : 0;
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 }
188 protected void structSectionForClass(PrintWriter pw,
189 TypeElement jclazz, String cname) {
191 String jname = jclazz.getQualifiedName().toString();
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));
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 }
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;
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 }
232 /* Returns "true" iff added a field. */
233 private boolean doField(FieldDefsRes res, VariableElement field,
234 String cname, boolean padWord) {
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 }
252 // Otherwise.
253 return false;
254 }
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());
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 }
271 String fieldDefs(TypeElement clazz, String cname) {
272 FieldDefsRes res = fieldDefs(clazz, cname, true);
273 return res.s;
274 }
276 FieldDefsRes fieldDefs(TypeElement clazz, String cname,
277 boolean bottomMost){
278 FieldDefsRes res;
279 int offset;
280 boolean didTwoWordFields = false;
282 TypeElement superclazz = (TypeElement) types.asElement(clazz.getSuperclass());
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 }
295 List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
297 for (VariableElement field: fields) {
299 if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {
300 offset = doTwoWordFields(res, clazz, offset, cname, false);
301 didTwoWordFields = true;
302 }
304 TypeKind tk = field.asType().getKind();
305 boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
307 if (!doubleAlign || !twoWords) {
308 if (doField(res, field, cname, false)) offset += 4;
309 }
311 }
313 if (doubleAlign && !didTwoWordFields) {
314 if ((offset % 8) != 0) offset += 4;
315 offset = doTwoWordFields(res, clazz, offset, cname, true);
316 }
318 res.byteSize = offset;
319 return res;
320 }
322 /* OVERRIDE: This method handles instance fields */
323 protected String addStructMember(VariableElement member, String cname,
324 boolean padWord) {
325 String res = null;
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 }
341 static private final boolean isWindows =
342 System.getProperty("os.name").startsWith("Windows");
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;
351 if (!field.getModifiers().contains(Modifier.STATIC))
352 return res;
353 if (!field.getModifiers().contains(Modifier.FINAL))
354 return res;
356 exp = field.getConstantValue();
358 if (exp != null) {
359 /* Constant. */
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 }
404 protected void methodSectionForClass(PrintWriter pw,
405 TypeElement clazz, String cname)
406 throws Util.Exit {
407 String methods = methodDecls(clazz, cname);
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 }
421 protected String methodDecls(TypeElement clazz, String cname) throws Util.Exit {
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 }
431 protected String methodDecl(ExecutableElement method,
432 TypeElement clazz, String cname)
433 throws Util.Exit {
434 String res = null;
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);
442 if (sig.charAt(0) != '(')
443 util.error("invalid.method.signature", sig);
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 }
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 }
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 }
476 protected final String jniMethodName(ExecutableElement method, String cname,
477 boolean longName) {
478 String res = "Java_" + cname + "_" + method.getSimpleName();
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 }
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 }
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);
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 }
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";
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 }
546 util.bug("jni.unknown.type");
547 return null; /* dead code. */
548 }
550 protected String llniType(TypeMirror t, boolean handleize, boolean longDoubleOK) {
551 String res = null;
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 }
573 case VOID:
574 res = "void";
575 break;
577 case BOOLEAN:
578 case BYTE:
579 case CHAR:
580 case SHORT:
581 case INT:
582 res = "java_int" ;
583 break;
585 case LONG:
586 res = longDoubleOK ? "java_long" : "val32 /* java_long */";
587 break;
589 case FLOAT:
590 res = "java_float";
591 break;
593 case DOUBLE:
594 res = longDoubleOK ? "java_double" : "val32 /* java_double */";
595 break;
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;
603 default:
604 throw new Error(t.getKind() + " " + t); // FIXME
605 }
607 return res;
608 }
610 protected final String cRcvrDecl(Element field, String cname) {
611 return (field.getModifiers().contains(Modifier.STATIC) ? "jclass" : "jobject");
612 }
614 protected String maskName(String s) {
615 return "LLNI_mask(" + s + ")";
616 }
618 protected String llniFieldName(VariableElement field) {
619 return maskName(field.getSimpleName().toString());
620 }
622 protected final boolean isLongOrDouble(TypeMirror t) {
623 TypeVisitor<Boolean,Void> v = new SimpleTypeVisitor7<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 }
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 }
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 }