Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/javah/LLNI.java
38899 views
/*1* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package com.sun.tools.javah;2728import java.io.OutputStream;29import java.io.PrintWriter;30import java.util.ArrayList;31import java.util.HashSet;32import java.util.List;3334import java.util.Set;35import javax.lang.model.element.Element;36import javax.lang.model.element.ExecutableElement;37import javax.lang.model.element.Modifier;38import javax.lang.model.element.Name;39import javax.lang.model.element.TypeElement;40import javax.lang.model.element.VariableElement;41import javax.lang.model.type.ArrayType;42import javax.lang.model.type.PrimitiveType;43import javax.lang.model.type.TypeKind;44import javax.lang.model.type.TypeMirror;45import javax.lang.model.type.TypeVisitor;46import javax.lang.model.util.ElementFilter;47import javax.lang.model.util.SimpleTypeVisitor8;4849/*50* <p><b>This is NOT part of any supported API.51* If you write code that depends on this, you do so at your own52* risk. This code and its internal interfaces are subject to change53* or deletion without notice.</b></p>54*55* @author Sucheta Dambalkar(Revised)56*/57public class LLNI extends Gen {5859protected final char innerDelim = '$'; /* For inner classes */60protected Set<String> doneHandleTypes;61List<VariableElement> fields;62List<ExecutableElement> methods;63private boolean doubleAlign;64private int padFieldNum = 0;6566LLNI(boolean doubleAlign, Util util) {67super(util);68this.doubleAlign = doubleAlign;69}7071protected String getIncludes() {72return "";73}7475protected void write(OutputStream o, TypeElement clazz) throws Util.Exit {76try {77String cname = mangleClassName(clazz.getQualifiedName().toString());78PrintWriter pw = wrapWriter(o);79fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());80methods = ElementFilter.methodsIn(clazz.getEnclosedElements());81generateDeclsForClass(pw, clazz, cname);82// FIXME check if errors occurred on the PrintWriter and throw exception if so83} catch (TypeSignature.SignatureException e) {84util.error("llni.sigerror", e.getMessage());85}86}8788protected void generateDeclsForClass(PrintWriter pw,89TypeElement clazz, String cname)90throws TypeSignature.SignatureException, Util.Exit {91doneHandleTypes = new HashSet<String>();92/* The following handle types are predefined in "typedefs.h". Suppress93inclusion in the output by generating them "into the blue" here. */94genHandleType(null, "java.lang.Class");95genHandleType(null, "java.lang.ClassLoader");96genHandleType(null, "java.lang.Object");97genHandleType(null, "java.lang.String");98genHandleType(null, "java.lang.Thread");99genHandleType(null, "java.lang.ThreadGroup");100genHandleType(null, "java.lang.Throwable");101102pw.println("/* LLNI Header for class " + clazz.getQualifiedName() + " */" + lineSep);103pw.println("#ifndef _Included_" + cname);104pw.println("#define _Included_" + cname);105pw.println("#include \"typedefs.h\"");106pw.println("#include \"llni.h\"");107pw.println("#include \"jni.h\"" + lineSep);108109forwardDecls(pw, clazz);110structSectionForClass(pw, clazz, cname);111methodSectionForClass(pw, clazz, cname);112pw.println("#endif");113}114115protected void genHandleType(PrintWriter pw, String clazzname) {116String cname = mangleClassName(clazzname);117if (!doneHandleTypes.contains(cname)) {118doneHandleTypes.add(cname);119if (pw != null) {120pw.println("#ifndef DEFINED_" + cname);121pw.println(" #define DEFINED_" + cname);122pw.println(" GEN_HANDLE_TYPES(" + cname + ");");123pw.println("#endif" + lineSep);124}125}126}127128protected String mangleClassName(String s) {129return s.replace('.', '_')130.replace('/', '_')131.replace(innerDelim, '_');132}133134protected void forwardDecls(PrintWriter pw, TypeElement clazz)135throws TypeSignature.SignatureException {136TypeElement object = elems.getTypeElement("java.lang.Object");137if (clazz.equals(object))138return;139140genHandleType(pw, clazz.getQualifiedName().toString());141TypeElement superClass = (TypeElement) (types.asElement(clazz.getSuperclass()));142143if (superClass != null) {144String superClassName = superClass.getQualifiedName().toString();145forwardDecls(pw, superClass);146}147148for (VariableElement field: fields) {149150if (!field.getModifiers().contains(Modifier.STATIC)) {151TypeMirror t = types.erasure(field.asType());152TypeSignature newTypeSig = new TypeSignature(elems);153String tname = newTypeSig.qualifiedTypeName(t);154String sig = newTypeSig.getTypeSignature(tname);155156if (sig.charAt(0) != '[')157forwardDeclsFromSig(pw, sig);158}159}160161for (ExecutableElement method: methods) {162163if (method.getModifiers().contains(Modifier.NATIVE)) {164TypeMirror retType = types.erasure(method.getReturnType());165String typesig = signature(method);166TypeSignature newTypeSig = new TypeSignature(elems);167String sig = newTypeSig.getTypeSignature(typesig, retType);168169if (sig.charAt(0) != '[')170forwardDeclsFromSig(pw, sig);171172}173}174}175176protected void forwardDeclsFromSig(PrintWriter pw, String sig) {177int len = sig.length();178int i = sig.charAt(0) == '(' ? 1 : 0;179180/* Skip the initial "(". */181while (i < len) {182if (sig.charAt(i) == 'L') {183int j = i + 1;184while (sig.charAt(j) != ';') j++;185genHandleType(pw, sig.substring(i + 1, j));186i = j + 1;187} else {188i++;189}190}191}192193protected void structSectionForClass(PrintWriter pw,194TypeElement jclazz, String cname) {195196String jname = jclazz.getQualifiedName().toString();197198if (cname.equals("java_lang_Object")) {199pw.println("/* struct java_lang_Object is defined in typedefs.h. */");200pw.println();201return;202}203pw.println("#if !defined(__i386)");204pw.println("#pragma pack(4)");205pw.println("#endif");206pw.println();207pw.println("struct " + cname + " {");208pw.println(" ObjHeader h;");209pw.print(fieldDefs(jclazz, cname));210211if (jname.equals("java.lang.Class"))212pw.println(" Class *LLNI_mask(cClass);" +213" /* Fake field; don't access (see oobj.h) */");214pw.println("};" + lineSep + lineSep + "#pragma pack()");215pw.println();216return;217}218219private static class FieldDefsRes {220public String className; /* Name of the current class. */221public FieldDefsRes parent;222public String s;223public int byteSize;224public boolean bottomMost;225public boolean printedOne = false;226227FieldDefsRes(TypeElement clazz, FieldDefsRes parent, boolean bottomMost) {228this.className = clazz.getQualifiedName().toString();229this.parent = parent;230this.bottomMost = bottomMost;231int byteSize = 0;232if (parent == null) this.s = "";233else this.s = parent.s;234}235}236237/* Returns "true" iff added a field. */238private boolean doField(FieldDefsRes res, VariableElement field,239String cname, boolean padWord) {240241String fieldDef = addStructMember(field, cname, padWord);242if (fieldDef != null) {243if (!res.printedOne) { /* add separator */244if (res.bottomMost) {245if (res.s.length() != 0)246res.s = res.s + " /* local members: */" + lineSep;247} else {248res.s = res.s + " /* inherited members from " +249res.className + ": */" + lineSep;250}251res.printedOne = true;252}253res.s = res.s + fieldDef;254return true;255}256257// Otherwise.258return false;259}260261private int doTwoWordFields(FieldDefsRes res, TypeElement clazz,262int offset, String cname, boolean padWord) {263boolean first = true;264List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());265266for (VariableElement field: fields) {267TypeKind tk = field.asType().getKind();268boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);269if (twoWords && doField(res, field, cname, first && padWord)) {270offset += 8; first = false;271}272}273return offset;274}275276String fieldDefs(TypeElement clazz, String cname) {277FieldDefsRes res = fieldDefs(clazz, cname, true);278return res.s;279}280281FieldDefsRes fieldDefs(TypeElement clazz, String cname,282boolean bottomMost){283FieldDefsRes res;284int offset;285boolean didTwoWordFields = false;286287TypeElement superclazz = (TypeElement) types.asElement(clazz.getSuperclass());288289if (superclazz != null) {290String supername = superclazz.getQualifiedName().toString();291res = new FieldDefsRes(clazz,292fieldDefs(superclazz, cname, false),293bottomMost);294offset = res.parent.byteSize;295} else {296res = new FieldDefsRes(clazz, null, bottomMost);297offset = 0;298}299300List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());301302for (VariableElement field: fields) {303304if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {305offset = doTwoWordFields(res, clazz, offset, cname, false);306didTwoWordFields = true;307}308309TypeKind tk = field.asType().getKind();310boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);311312if (!doubleAlign || !twoWords) {313if (doField(res, field, cname, false)) offset += 4;314}315316}317318if (doubleAlign && !didTwoWordFields) {319if ((offset % 8) != 0) offset += 4;320offset = doTwoWordFields(res, clazz, offset, cname, true);321}322323res.byteSize = offset;324return res;325}326327/* OVERRIDE: This method handles instance fields */328protected String addStructMember(VariableElement member, String cname,329boolean padWord) {330String res = null;331332if (member.getModifiers().contains(Modifier.STATIC)) {333res = addStaticStructMember(member, cname);334// if (res == null) /* JNI didn't handle it, print comment. */335// res = " /* Inaccessible static: " + member + " */" + lineSep;336} else {337TypeMirror mt = types.erasure(member.asType());338if (padWord) res = " java_int padWord" + padFieldNum++ + ";" + lineSep;339res = " " + llniType(mt, false, false) + " " + llniFieldName(member);340if (isLongOrDouble(mt)) res = res + "[2]";341res = res + ";" + lineSep;342}343return res;344}345346static private final boolean isWindows =347System.getProperty("os.name").startsWith("Windows");348349/*350* This method only handles static final fields.351*/352protected String addStaticStructMember(VariableElement field, String cname) {353String res = null;354Object exp = null;355356if (!field.getModifiers().contains(Modifier.STATIC))357return res;358if (!field.getModifiers().contains(Modifier.FINAL))359return res;360361exp = field.getConstantValue();362363if (exp != null) {364/* Constant. */365366String cn = cname + "_" + field.getSimpleName();367String suffix = null;368long val = 0;369/* Can only handle int, long, float, and double fields. */370if (exp instanceof Byte371|| exp instanceof Short372|| exp instanceof Integer) {373suffix = "L";374val = ((Number)exp).intValue();375}376else if (exp instanceof Long) {377// Visual C++ supports the i64 suffix, not LL378suffix = isWindows ? "i64" : "LL";379val = ((Long)exp).longValue();380}381else if (exp instanceof Float) suffix = "f";382else if (exp instanceof Double) suffix = "";383else if (exp instanceof Character) {384suffix = "L";385Character ch = (Character) exp;386val = ((int) ch) & 0xffff;387}388if (suffix != null) {389// Some compilers will generate a spurious warning390// for the integer constants for Integer.MIN_VALUE391// and Long.MIN_VALUE so we handle them specially.392if ((suffix.equals("L") && (val == Integer.MIN_VALUE)) ||393(suffix.equals("LL") && (val == Long.MIN_VALUE))) {394res = " #undef " + cn + lineSep395+ " #define " + cn396+ " (" + (val + 1) + suffix + "-1)" + lineSep;397} else if (suffix.equals("L") || suffix.endsWith("LL")) {398res = " #undef " + cn + lineSep399+ " #define " + cn + " " + val + suffix + lineSep;400} else {401res = " #undef " + cn + lineSep402+ " #define " + cn + " " + exp + suffix + lineSep;403}404}405}406return res;407}408409protected void methodSectionForClass(PrintWriter pw,410TypeElement clazz, String cname)411throws TypeSignature.SignatureException, Util.Exit {412String methods = methodDecls(clazz, cname);413414if (methods.length() != 0) {415pw.println("/* Native method declarations: */" + lineSep);416pw.println("#ifdef __cplusplus");417pw.println("extern \"C\" {");418pw.println("#endif" + lineSep);419pw.println(methods);420pw.println("#ifdef __cplusplus");421pw.println("}");422pw.println("#endif");423}424}425426protected String methodDecls(TypeElement clazz, String cname)427throws TypeSignature.SignatureException, Util.Exit {428429String res = "";430for (ExecutableElement method: methods) {431if (method.getModifiers().contains(Modifier.NATIVE))432res = res + methodDecl(method, clazz, cname);433}434return res;435}436437protected String methodDecl(ExecutableElement method,438TypeElement clazz, String cname)439throws TypeSignature.SignatureException, Util.Exit {440String res = null;441442TypeMirror retType = types.erasure(method.getReturnType());443String typesig = signature(method);444TypeSignature newTypeSig = new TypeSignature(elems);445String sig = newTypeSig.getTypeSignature(typesig, retType);446boolean longName = needLongName(method, clazz);447448if (sig.charAt(0) != '(')449util.error("invalid.method.signature", sig);450451452res = "JNIEXPORT " + jniType(retType) + " JNICALL" + lineSep + jniMethodName(method, cname, longName)453+ "(JNIEnv *, " + cRcvrDecl(method, cname);454List<? extends VariableElement> params = method.getParameters();455List<TypeMirror> argTypes = new ArrayList<TypeMirror>();456for (VariableElement p: params){457argTypes.add(types.erasure(p.asType()));458}459460/* It would have been nice to include the argument names in the461declaration, but there seems to be a bug in the "BinaryField"462class, causing the getArguments() method to return "null" for463most (non-constructor) methods. */464for (TypeMirror argType: argTypes)465res = res + ", " + jniType(argType);466res = res + ");" + lineSep;467return res;468}469470protected final boolean needLongName(ExecutableElement method,471TypeElement clazz) {472Name methodName = method.getSimpleName();473for (ExecutableElement memberMethod: methods) {474if ((memberMethod != method) &&475memberMethod.getModifiers().contains(Modifier.NATIVE) &&476(methodName.equals(memberMethod.getSimpleName())))477return true;478}479return false;480}481482protected final String jniMethodName(ExecutableElement method, String cname,483boolean longName)484throws TypeSignature.SignatureException {485String res = "Java_" + cname + "_" + method.getSimpleName();486487if (longName) {488TypeMirror mType = types.erasure(method.getReturnType());489List<? extends VariableElement> params = method.getParameters();490List<TypeMirror> argTypes = new ArrayList<TypeMirror>();491for (VariableElement param: params) {492argTypes.add(types.erasure(param.asType()));493}494495res = res + "__";496for (TypeMirror t: argTypes) {497String tname = t.toString();498TypeSignature newTypeSig = new TypeSignature(elems);499String sig = newTypeSig.getTypeSignature(tname);500res = res + nameToIdentifier(sig);501}502}503return res;504}505506// copied from JNI.java507protected final String jniType(TypeMirror t) throws Util.Exit {508TypeElement throwable = elems.getTypeElement("java.lang.Throwable");509TypeElement jClass = elems.getTypeElement("java.lang.Class");510TypeElement jString = elems.getTypeElement("java.lang.String");511Element tclassDoc = types.asElement(t);512513switch (t.getKind()) {514case ARRAY: {515TypeMirror ct = ((ArrayType) t).getComponentType();516switch (ct.getKind()) {517case BOOLEAN: return "jbooleanArray";518case BYTE: return "jbyteArray";519case CHAR: return "jcharArray";520case SHORT: return "jshortArray";521case INT: return "jintArray";522case LONG: return "jlongArray";523case FLOAT: return "jfloatArray";524case DOUBLE: return "jdoubleArray";525case ARRAY:526case DECLARED: return "jobjectArray";527default: throw new Error(ct.toString());528}529}530531case VOID: return "void";532case BOOLEAN: return "jboolean";533case BYTE: return "jbyte";534case CHAR: return "jchar";535case SHORT: return "jshort";536case INT: return "jint";537case LONG: return "jlong";538case FLOAT: return "jfloat";539case DOUBLE: return "jdouble";540541case DECLARED: {542if (tclassDoc.equals(jString))543return "jstring";544else if (types.isAssignable(t, throwable.asType()))545return "jthrowable";546else if (types.isAssignable(t, jClass.asType()))547return "jclass";548else549return "jobject";550}551}552553util.bug("jni.unknown.type");554return null; /* dead code. */555}556557protected String llniType(TypeMirror t, boolean handleize, boolean longDoubleOK) {558String res = null;559560switch (t.getKind()) {561case ARRAY: {562TypeMirror ct = ((ArrayType) t).getComponentType();563switch (ct.getKind()) {564case BOOLEAN: res = "IArrayOfBoolean"; break;565case BYTE: res = "IArrayOfByte"; break;566case CHAR: res = "IArrayOfChar"; break;567case SHORT: res = "IArrayOfShort"; break;568case INT: res = "IArrayOfInt"; break;569case LONG: res = "IArrayOfLong"; break;570case FLOAT: res = "IArrayOfFloat"; break;571case DOUBLE: res = "IArrayOfDouble"; break;572case ARRAY:573case DECLARED: res = "IArrayOfRef"; break;574default: throw new Error(ct.getKind() + " " + ct);575}576if (!handleize) res = "DEREFERENCED_" + res;577break;578}579580case VOID:581res = "void";582break;583584case BOOLEAN:585case BYTE:586case CHAR:587case SHORT:588case INT:589res = "java_int" ;590break;591592case LONG:593res = longDoubleOK ? "java_long" : "val32 /* java_long */";594break;595596case FLOAT:597res = "java_float";598break;599600case DOUBLE:601res = longDoubleOK ? "java_double" : "val32 /* java_double */";602break;603604case DECLARED:605TypeElement e = (TypeElement) types.asElement(t);606res = "I" + mangleClassName(e.getQualifiedName().toString());607if (!handleize) res = "DEREFERENCED_" + res;608break;609610default:611throw new Error(t.getKind() + " " + t); // FIXME612}613614return res;615}616617protected final String cRcvrDecl(Element field, String cname) {618return (field.getModifiers().contains(Modifier.STATIC) ? "jclass" : "jobject");619}620621protected String maskName(String s) {622return "LLNI_mask(" + s + ")";623}624625protected String llniFieldName(VariableElement field) {626return maskName(field.getSimpleName().toString());627}628629protected final boolean isLongOrDouble(TypeMirror t) {630TypeVisitor<Boolean,Void> v = new SimpleTypeVisitor8<Boolean,Void>() {631public Boolean defaultAction(TypeMirror t, Void p){632return false;633}634public Boolean visitArray(ArrayType t, Void p) {635return visit(t.getComponentType(), p);636}637public Boolean visitPrimitive(PrimitiveType t, Void p) {638TypeKind tk = t.getKind();639return (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);640}641};642return v.visit(t, null);643}644645/* Do unicode to ansi C identifier conversion.646%%% This may not be right, but should be called more often. */647protected final String nameToIdentifier(String name) {648int len = name.length();649StringBuilder buf = new StringBuilder(len);650for (int i = 0; i < len; i++) {651char c = name.charAt(i);652if (isASCIILetterOrDigit(c))653buf.append(c);654else if (c == '/')655buf.append('_');656else if (c == '.')657buf.append('_');658else if (c == '_')659buf.append("_1");660else if (c == ';')661buf.append("_2");662else if (c == '[')663buf.append("_3");664else665buf.append("_0" + ((int)c));666}667return new String(buf);668}669670protected final boolean isASCIILetterOrDigit(char c) {671if (((c >= 'A') && (c <= 'Z')) ||672((c >= 'a') && (c <= 'z')) ||673((c >= '0') && (c <= '9')))674return true;675else676return false;677}678}679680681682