Providing JavaScript specific implementations of Hashtable and Vector. Those should likely be faster for the JavaScript VM than interpreting bytecode. This is the way to get the best of JavaScript and yet provide reasonably well working implementation in Java.
2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.vm4brwsr;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import org.apidesign.bck2brwsr.core.JavaScriptBody;
23 import org.apidesign.javap.AnnotationParser;
24 import org.apidesign.javap.ClassData;
25 import org.apidesign.javap.FieldData;
26 import org.apidesign.javap.MethodData;
27 import static org.apidesign.javap.RuntimeConstants.*;
29 /** Translator of the code inside class files to JavaScript.
31 * @author Jaroslav Tulach <jtulach@netbeans.org>
33 abstract class ByteCodeToJavaScript {
37 protected ByteCodeToJavaScript(Appendable out) {
41 /* Collects additional required resources.
43 * @param internalClassName classes that were referenced and should be loaded in order the
44 * generated JavaScript code works properly. The names are in internal
45 * JVM form so String is <code>java/lang/String</code>.
47 protected abstract boolean requireReference(String internalClassName);
50 * @param resourcePath name of resources to read
52 protected abstract void requireScript(String resourcePath);
54 /** Allows subclasses to redefine what field a function representing a
55 * class gets assigned. By default it returns the suggested name followed
56 * by <code>" = "</code>;
58 * @param className suggested name of the class
60 /* protected */ String assignClass(String className) {
61 return className + " = ";
63 /* protected */ String accessClass(String classOperation) {
64 return classOperation;
68 * Converts a given class file to a JavaScript version.
70 * @param classFile input stream with code of the .class file
71 * @return the initialization code for this class, if any. Otherwise <code>null</code>
73 * @throws IOException if something goes wrong during read or write or translating
76 public String compile(InputStream classFile) throws IOException {
77 this.jc = new ClassData(classFile);
78 byte[] arrData = jc.findAnnotationData(true);
79 String[] arr = findAnnotation(arrData, jc,
80 "org.apidesign.bck2brwsr.core.ExtraJavaScript",
81 "resource", "processByteCode"
84 requireScript(arr[0]);
85 if ("0".equals(arr[1])) {
89 String[] proto = findAnnotation(arrData, jc,
90 "org.apidesign.bck2brwsr.core.JavaScriptPrototype",
91 "container", "prototype"
93 StringArray toInitilize = new StringArray();
94 final String className = className(jc);
95 out.append("\n\n").append(assignClass(className));
96 out.append("function CLS() {");
97 out.append("\n if (!CLS.prototype.$instOf_").append(className).append(") {");
98 for (FieldData v : jc.getFields()) {
100 out.append("\n CLS.").append(v.getName()).append(initField(v));
104 String sc = jc.getSuperClassName(); // with _
105 out.append("\n var pp = ").
106 append(accessClass(sc.replace('/', '_'))).append("(true);");
107 out.append("\n var p = CLS.prototype = pp;");
108 out.append("\n var c = p;");
109 out.append("\n var sprcls = pp.constructor.$class;");
111 out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";");
112 if (proto[0] == null) {
115 out.append("\n var c = ").append(proto[0]).append(";");
116 out.append("\n var sprcls = null;");
118 for (MethodData m : jc.getMethods()) {
119 byte[] onlyArr = m.findAnnotationData(true);
120 String[] only = findAnnotation(onlyArr, jc,
121 "org.apidesign.bck2brwsr.core.JavaScriptOnly",
125 if (only[0] != null && only[1] != null) {
126 out.append("\n p.").append(only[0]).append(" = ")
127 .append(only[1]).append(";");
133 mn = generateStaticMethod("\n c.", m, toInitilize);
135 mn = generateInstanceMethod("\n c.", m);
137 byte[] runAnno = m.findAnnotationData(false);
138 if (runAnno != null) {
139 out.append("\n c.").append(mn).append(".anno = {");
140 generateAnno(jc, out, runAnno);
144 out.append("\n c.constructor = CLS;");
145 out.append("\n c.$instOf_").append(className).append(" = true;");
146 for (String superInterface : jc.getSuperInterfaces()) {
147 out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
149 out.append("\n CLS.$class = ");
150 out.append(accessClass("java_lang_Class(true);"));
151 out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
152 out.append("\n CLS.$class.superclass = sprcls;");
153 out.append("\n CLS.$class.cnstr = CLS;");
154 byte[] classAnno = jc.findAnnotationData(false);
155 if (classAnno != null) {
156 out.append("\n CLS.$class.anno = {");
157 generateAnno(jc, out, classAnno);
161 out.append("\n if (arguments.length === 0) {");
162 out.append("\n if (!(this instanceof CLS)) {");
163 out.append("\n return new CLS();");
165 for (FieldData v : jc.getFields()) {
166 byte[] onlyArr = v.findAnnotationData(true);
167 String[] only = findAnnotation(onlyArr, jc,
168 "org.apidesign.bck2brwsr.core.JavaScriptOnly",
172 if (only[0] != null && only[1] != null) {
173 out.append("\n p.").append(only[0]).append(" = ")
174 .append(only[1]).append(";");
179 out.append("\n this.fld_").
180 append(v.getName()).append(initField(v));
183 out.append("\n return this;");
185 out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
187 StringBuilder sb = new StringBuilder();
188 for (String init : toInitilize.toArray()) {
189 sb.append("\n").append(init).append("();");
191 return sb.toString();
193 private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
194 String jsb = javaScriptBody(prefix, m, true);
198 StringBuilder argsCnt = new StringBuilder();
199 final String mn = findMethodName(m, argsCnt);
200 out.append(prefix).append(mn).append(" = function");
201 if (mn.equals("class__V")) {
202 toInitilize.add(accessClass(className(jc)) + "(false)." + mn);
206 for (int index = 0, i = 0; i < argsCnt.length(); i++) {
208 out.append("arg").append(String.valueOf(index));
210 final String desc = null;// XXX findDescriptor(args.get(i).getDescriptor());
211 if (argsCnt.charAt(i) == '1') {
217 out.append(") {").append("\n");
218 final byte[] code = m.getCode();
220 int len = m.getMaxLocals();
221 for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
223 out.append("arg").append(String.valueOf(i)).append(";\n");
225 out.append(" var s = new Array();\n");
228 out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n");
234 private String generateInstanceMethod(String prefix, MethodData m) throws IOException {
235 String jsb = javaScriptBody(prefix, m, false);
239 StringBuilder argsCnt = new StringBuilder();
240 final String mn = findMethodName(m, argsCnt);
241 out.append(prefix).append(mn).append(" = function");
244 for (int index = 1, i = 0; i < argsCnt.length(); i++) {
246 out.append("arg").append(String.valueOf(index));
247 if (argsCnt.charAt(i) == '1') {
253 out.append(") {").append("\n");
254 final byte[] code = m.getCode();
256 int len = m.getMaxLocals();
257 for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
259 out.append("arg").append(String.valueOf(i + 1)).append(";\n");
261 out.append(";\n var s = new Array();\n");
264 out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n");
270 private void produceCode(byte[] byteCodes) throws IOException {
271 out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
272 for (int i = 0; i < byteCodes.length; i++) {
274 out.append(" case " + i).append(": ");
275 final int c = readByte(byteCodes, i);
282 out.append("s.push(arg0);");
289 out.append("s.push(arg1);");
296 out.append("s.push(arg2);");
303 out.append("s.push(arg3);");
310 final int indx = readByte(byteCodes, ++i);
311 out.append("s.push(arg").append(indx + ");");
319 final int indx = readByte(byteCodes, ++i);
320 out.append("arg" + indx).append(" = s.pop();");
328 out.append("arg0 = s.pop();");
335 out.append("arg1 = s.pop();");
342 out.append("arg2 = s.pop();");
349 out.append("arg3 = s.pop();");
355 out.append("s.push(s.pop() + s.pop());");
361 out.append("{ var tmp = s.pop(); s.push(s.pop() - tmp); }");
367 out.append("s.push(s.pop() * s.pop());");
371 out.append("{ var tmp = s.pop(); s.push(Math.floor(s.pop() / tmp)); }");
375 out.append("{ var tmp = s.pop(); s.push(s.pop() / tmp); }");
381 out.append("{ var d = s.pop(); s.push(s.pop() % d); }");
385 out.append("s.push(s.pop() & s.pop());");
389 out.append("s.push(s.pop() | s.pop());");
393 out.append("s.push(s.pop() ^ s.pop());");
399 out.append("s.push(- s.pop());");
403 out.append("{ var v = s.pop(); s.push(s.pop() << v); }");
407 out.append("{ var v = s.pop(); s.push(s.pop() >> v); }");
411 out.append("{ var v = s.pop(); s.push(s.pop() >>> v); }");
414 final int varIndx = readByte(byteCodes, ++i);
415 final int incrBy = byteCodes[++i];
417 out.append("arg" + varIndx).append("++;");
419 out.append("arg" + varIndx).append(" += " + incrBy).append(";");
424 out.append("return;");
431 out.append("return s.pop();");
442 out.append("/* number conversion */");
448 out.append("s.push(Math.floor(s.pop()));");
453 out.append("/* number conversion */");
455 case opc_aconst_null:
456 out.append("s.push(null);");
459 out.append("s.push(-1);");
465 out.append("s.push(0);");
471 out.append("s.push(1);");
475 out.append("s.push(2);");
478 out.append("s.push(3);");
481 out.append("s.push(4);");
484 out.append("s.push(5);");
487 int indx = readByte(byteCodes, ++i);
488 String v = encodeConstant(indx);
489 out.append("s.push(").append(v).append(");");
494 int indx = readIntArg(byteCodes, i);
496 String v = encodeConstant(indx);
497 out.append("s.push(").append(v).append(");");
505 out.append("{ var delta = s.pop() - s.pop(); s.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }");
509 i = generateIf(byteCodes, i, "===");
512 i = generateIf(byteCodes, i, "!=");
514 case opc_if_icmpeq: {
515 i = generateIf(byteCodes, i, "==");
519 int indx = i + readIntArg(byteCodes, i);
520 out.append("if (s.pop() == 0) { gt = " + indx);
521 out.append("; continue; }");
526 int indx = i + readIntArg(byteCodes, i);
527 out.append("if (s.pop() != 0) { gt = " + indx);
528 out.append("; continue; }");
533 int indx = i + readIntArg(byteCodes, i);
534 out.append("if (s.pop() < 0) { gt = " + indx);
535 out.append("; continue; }");
540 int indx = i + readIntArg(byteCodes, i);
541 out.append("if (s.pop() <= 0) { gt = " + indx);
542 out.append("; continue; }");
547 int indx = i + readIntArg(byteCodes, i);
548 out.append("if (s.pop() > 0) { gt = " + indx);
549 out.append("; continue; }");
554 int indx = i + readIntArg(byteCodes, i);
555 out.append("if (s.pop() >= 0) { gt = " + indx);
556 out.append("; continue; }");
560 case opc_ifnonnull: {
561 int indx = i + readIntArg(byteCodes, i);
562 out.append("if (s.pop() !== null) { gt = " + indx);
563 out.append("; continue; }");
568 int indx = i + readIntArg(byteCodes, i);
569 out.append("if (s.pop() === null) { gt = " + indx);
570 out.append("; continue; }");
575 i = generateIf(byteCodes, i, "!=");
578 i = generateIf(byteCodes, i, ">");
581 i = generateIf(byteCodes, i, ">=");
584 i = generateIf(byteCodes, i, "<");
587 i = generateIf(byteCodes, i, "<=");
590 int indx = i + readIntArg(byteCodes, i);
591 out.append("gt = " + indx).append("; continue;");
595 case opc_lookupswitch: {
596 int table = i / 4 * 4 + 4;
597 int dflt = i + readInt4(byteCodes, table);
599 int n = readInt4(byteCodes, table);
601 out.append("switch (s.pop()) {\n");
603 int cnstnt = readInt4(byteCodes, table);
605 int offset = i + readInt4(byteCodes, table);
607 out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
609 out.append(" default: gt = " + dflt).append("; continue;\n}");
613 case opc_tableswitch: {
614 int table = i / 4 * 4 + 4;
615 int dflt = i + readInt4(byteCodes, table);
617 int low = readInt4(byteCodes, table);
619 int high = readInt4(byteCodes, table);
621 out.append("switch (s.pop()) {\n");
622 while (low <= high) {
623 int offset = i + readInt4(byteCodes, table);
625 out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
628 out.append(" default: gt = " + dflt).append("; continue;\n}");
632 case opc_invokeinterface: {
633 i = invokeVirtualMethod(byteCodes, i) + 2;
636 case opc_invokevirtual:
637 i = invokeVirtualMethod(byteCodes, i);
639 case opc_invokespecial:
640 i = invokeStaticMethod(byteCodes, i, false);
642 case opc_invokestatic:
643 i = invokeStaticMethod(byteCodes, i, true);
646 int indx = readIntArg(byteCodes, i);
647 String ci = jc.getClassName(indx);
648 out.append("s.push(new ");
649 out.append(accessClass(ci.replace('/','_')));
656 int type = byteCodes[i++];
657 out.append("s.push(new Array(s.pop()).fillNulls());");
660 case opc_anewarray: {
661 i += 2; // skip type of array
662 out.append("s.push(new Array(s.pop()).fillNulls());");
665 case opc_multianewarray: {
667 int dim = readByte(byteCodes, ++i);
668 out.append("{ var a0 = new Array(s.pop()).fillNulls();");
669 for (int d = 1; d < dim; d++) {
670 out.append("\n var l" + d).append(" = s.pop();");
671 out.append("\n for (var i" + d).append (" = 0; i" + d).
672 append(" < a" + (d - 1)).
673 append(".length; i" + d).append("++) {");
674 out.append("\n var a" + d).
675 append (" = new Array(l" + d).append(").fillNulls();");
676 out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d).
679 for (int d = 1; d < dim; d++) {
682 out.append("\ns.push(a0); }");
685 case opc_arraylength:
686 out.append("s.push(s.pop().length);");
696 out.append("{ var value = s.pop(); var indx = s.pop(); s.pop()[indx] = value; }");
707 out.append("{ var indx = s.pop(); s.push(s.pop()[indx]); }");
711 out.append("s.pop();");
713 out.append("s.pop();");
716 out.append("s.push(s[s.length - 1]);");
719 out.append("{ var v1 = s.pop(); var v2 = s.pop(); s.push(v1); s.push(v2); s.push(v1); }");
722 out.append("{ var v1 = s.pop(); var v2 = s.pop(); var v3 = s.pop(); s.push(v1); s.push(v3); s.push(v2); s.push(v1); }");
725 out.append("s.push(" + byteCodes[++i] + ");");
728 out.append("s.push(" + readIntArg(byteCodes, i) + ");");
732 int indx = readIntArg(byteCodes, i);
733 String[] fi = jc.getFieldInfoName(indx);
734 out.append("s.push(s.pop().fld_").
735 append(fi[1]).append(");");
739 case opc_getstatic: {
740 int indx = readIntArg(byteCodes, i);
741 String[] fi = jc.getFieldInfoName(indx);
742 out.append("s.push(").append(accessClass(fi[0].replace('/', '_')));
743 out.append('.').append(fi[1]).append(");");
748 case opc_putstatic: {
749 int indx = readIntArg(byteCodes, i);
750 String[] fi = jc.getFieldInfoName(indx);
751 out.append(accessClass(fi[0].replace('/', '_')));
752 out.append('.').append(fi[1]).append(" = s.pop();");
758 int indx = readIntArg(byteCodes, i);
759 String[] fi = jc.getFieldInfoName(indx);
760 out.append("{ var v = s.pop(); s.pop().fld_")
761 .append(fi[1]).append(" = v; }");
765 case opc_checkcast: {
766 int indx = readIntArg(byteCodes, i);
767 final String type = jc.getClassName(indx);
768 if (!type.startsWith("[")) {
769 // no way to check arrays right now
770 out.append("if(s[s.length - 1] !== null && !s[s.length - 1].$instOf_")
771 .append(type.replace('/', '_'))
772 .append(") throw {};"); // XXX proper exception
777 case opc_instanceof: {
778 int indx = readIntArg(byteCodes, i);
779 final String type = jc.getClassName(indx);
780 out.append("s.push(s.pop().$instOf_")
781 .append(type.replace('/', '_'))
782 .append(" ? 1 : 0);");
787 out.append("{ var t = s.pop(); s = new Array(1); s[0] = t; throw t; }");
791 out.append("throw 'unknown bytecode " + c + "';");
796 for (int j = prev; j <= i; j++) {
798 final int cc = readByte(byteCodes, j);
799 out.append(Integer.toString(cc));
806 private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
807 int indx = i + readIntArg(byteCodes, i);
808 out.append("if (s.pop() ").append(test).append(" s.pop()) { gt = " + indx);
809 out.append("; continue; }");
813 private int readIntArg(byte[] byteCodes, int offsetInstruction) {
814 final int indxHi = byteCodes[offsetInstruction + 1] << 8;
815 final int indxLo = byteCodes[offsetInstruction + 2];
816 return (indxHi & 0xffffff00) | (indxLo & 0xff);
818 private int readInt4(byte[] byteCodes, int offsetInstruction) {
819 final int d = byteCodes[offsetInstruction + 0] << 24;
820 final int c = byteCodes[offsetInstruction + 1] << 16;
821 final int b = byteCodes[offsetInstruction + 2] << 8;
822 final int a = byteCodes[offsetInstruction + 3];
823 return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
825 private int readByte(byte[] byteCodes, int offsetInstruction) {
826 return (byteCodes[offsetInstruction] + 256) % 256;
829 private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) {
831 Boolean count = null;
832 boolean array = false;
834 int firstPos = sig.length();
835 while (i < descriptor.length()) {
836 char ch = descriptor.charAt(i++);
857 if (ch == 'J' || ch == 'D') {
863 hasReturnType[0] = true;
864 sig.insert(firstPos, ch);
866 sig.insert(firstPos, "_3");
873 hasReturnType[0] = false;
874 sig.insert(firstPos, 'V');
877 int next = descriptor.indexOf(';', i);
878 String realSig = mangleSig(descriptor, i - 1, next + 1);
886 sig.insert(firstPos, realSig);
888 sig.insert(firstPos, "_3");
890 hasReturnType[0] = true;
898 throw new IllegalStateException("Invalid char: " + ch);
903 private static String mangleSig(String txt, int first, int last) {
904 StringBuilder sb = new StringBuilder();
905 for (int i = first; i < last; i++) {
906 final char ch = txt.charAt(i);
908 case '/': sb.append('_'); break;
909 case '_': sb.append("_1"); break;
910 case ';': sb.append("_2"); break;
911 case '[': sb.append("_3"); break;
912 default: sb.append(ch); break;
915 return sb.toString();
918 private static String findMethodName(MethodData m, StringBuilder cnt) {
919 StringBuilder name = new StringBuilder();
920 if ("<init>".equals(m.getName())) { // NOI18N
921 name.append("cons"); // NOI18N
922 } else if ("<clinit>".equals(m.getName())) { // NOI18N
923 name.append("class"); // NOI18N
925 name.append(m.getName());
928 boolean hasReturn[] = { false };
929 countArgs(m.getInternalSig(), hasReturn, name, cnt);
930 return name.toString();
933 static String findMethodName(String[] mi, StringBuilder cnt, boolean[] hasReturn) {
934 StringBuilder name = new StringBuilder();
935 String descr = mi[2];//mi.getDescriptor();
937 if ("<init>".equals(nm)) { // NOI18N
938 name.append("cons"); // NOI18N
942 countArgs(descr, hasReturn, name, cnt);
943 return name.toString();
946 private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
948 int methodIndex = readIntArg(byteCodes, i);
949 String[] mi = jc.getFieldInfoName(methodIndex);
950 boolean[] hasReturn = { false };
951 StringBuilder cnt = new StringBuilder();
952 String mn = findMethodName(mi, cnt, hasReturn);
954 for (int j = cnt.length() - 1; j >= 0; j--) {
955 out.append("var v" + j).append(" = s.pop(); ");
959 out.append("s.push(");
961 final String in = mi[0];
962 out.append(accessClass(in.replace('/', '_')));
963 out.append("(false).");
968 out.append("s.pop()");
971 for (int j = 0; j < cnt.length(); j++) {
985 private int invokeVirtualMethod(byte[] byteCodes, int i)
987 int methodIndex = readIntArg(byteCodes, i);
988 String[] mi = jc.getFieldInfoName(methodIndex);
989 boolean[] hasReturn = { false };
990 StringBuilder cnt = new StringBuilder();
991 String mn = findMethodName(mi, cnt, hasReturn);
993 for (int j = cnt.length() - 1; j >= 0; j--) {
994 out.append("var v" + j).append(" = s.pop(); ");
996 out.append("var self = s.pop(); ");
998 out.append("s.push(");
1000 out.append("self.");
1004 for (int j = 0; j < cnt.length(); j++) {
1006 out.append("v" + j);
1017 private void addReference(String cn) throws IOException {
1018 if (requireReference(cn)) {
1019 out.append(" /* needs ").append(cn).append(" */");
1023 private void outType(String d, StringBuilder out) {
1025 while (d.charAt(0) == '[') {
1029 if (d.charAt(0) == 'L') {
1030 assert d.charAt(d.length() - 1) == ';';
1031 out.append(d.replace('/', '_').substring(0, d.length() - 1));
1037 private String encodeConstant(int entryIndex) throws IOException {
1038 String[] classRef = { null };
1039 String s = jc.stringValue(entryIndex, classRef);
1040 if (classRef[0] != null) {
1041 addReference(classRef[0]);
1042 s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
1047 private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
1048 byte[] arr = m.findAnnotationData(true);
1052 final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
1053 class P extends AnnotationParser {
1059 String[] args = new String[30];
1063 protected void visitAttr(String type, String attr, String at, String value) {
1064 if (type.equals(jvmType)) {
1065 if ("body".equals(attr)) {
1067 } else if ("args".equals(attr)) {
1068 args[cnt++] = value;
1070 throw new IllegalArgumentException(attr);
1077 if (p.body == null) {
1080 StringBuilder cnt = new StringBuilder();
1081 final String mn = findMethodName(m, cnt);
1082 out.append(prefix).append(mn);
1083 out.append(" = function(");
1087 space = outputArg(out, p.args, 0);
1093 for (int i = 0; i < cnt.length(); i++) {
1095 space = outputArg(out, p.args, index);
1098 out.append(") {").append("\n");
1100 out.append("\n}\n");
1103 private static String className(ClassData jc) {
1104 //return jc.getName().getInternalName().replace('/', '_');
1105 return jc.getClassName().replace('/', '_');
1108 private static String[] findAnnotation(
1109 byte[] arr, ClassData cd, final String className,
1110 final String... attrNames
1111 ) throws IOException {
1115 final String[] values = new String[attrNames.length];
1116 final boolean[] found = { false };
1117 final String jvmType = "L" + className.replace('.', '/') + ";";
1118 AnnotationParser ap = new AnnotationParser(false) {
1120 protected void visitAttr(String type, String attr, String at, String value) {
1121 if (type.equals(jvmType)) {
1123 for (int i = 0; i < attrNames.length; i++) {
1124 if (attrNames[i].equals(attr)) {
1133 return found[0] ? values : null;
1136 private CharSequence initField(FieldData v) {
1137 final String is = v.getInternalSig();
1138 if (is.length() == 1) {
1139 switch (is.charAt(0)) {
1145 case 'I': return " = 0;";
1147 case 'D': return " = 0.0;";
1149 throw new IllegalStateException(is);
1155 private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
1156 AnnotationParser ap = new AnnotationParser(true) {
1161 protected void visitAnnotationStart(String type) throws IOException {
1165 out.append('"').append(type).append("\" : {\n");
1170 protected void visitAnnotationEnd(String type) throws IOException {
1171 out.append("\n}\n");
1175 protected void visitAttr(String type, String attr, String attrType, String value)
1176 throws IOException {
1183 out.append(attr).append("__").append(attrType).append(" : ").append(value);
1189 private static String outputArg(Appendable out, String[] args, int indx) throws IOException {
1190 final String name = args[indx];
1194 if (name.contains(",")) {
1195 throw new IOException("Wrong parameter with ',': " + name);