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 org.apidesign.javap.StackMapIterator;
28 import static org.apidesign.javap.RuntimeConstants.*;
30 /** Translator of the code inside class files to JavaScript.
32 * @author Jaroslav Tulach <jtulach@netbeans.org>
34 public abstract class ByteCodeToJavaScript {
36 private final Appendable out;
38 protected ByteCodeToJavaScript(Appendable out) {
42 /* Collects additional required resources.
44 * @param internalClassName classes that were referenced and should be loaded in order the
45 * generated JavaScript code works properly. The names are in internal
46 * JVM form so String is <code>java/lang/String</code>.
48 protected abstract boolean requireReference(String internalClassName);
51 * @param resourcePath name of resources to read
53 protected abstract void requireScript(String resourcePath);
56 * Converts a given class file to a JavaScript version.
58 * @param classFile input stream with code of the .class file
59 * @return the initialization code for this class, if any. Otherwise <code>null</code>
61 * @throws IOException if something goes wrong during read or write or translating
64 public String compile(InputStream classFile) throws IOException {
65 this.jc = new ClassData(classFile);
66 byte[] arrData = jc.findAnnotationData(true);
67 String[] arr = findAnnotation(arrData, jc,
68 "org.apidesign.bck2brwsr.core.ExtraJavaScript",
69 "resource", "processByteCode"
72 requireScript(arr[0]);
73 if ("0".equals(arr[1])) {
77 StringArray toInitilize = new StringArray();
78 for (MethodData m : jc.getMethods()) {
80 generateStaticMethod(m, toInitilize);
82 generateInstanceMethod(m);
85 final String className = className(jc);
86 out.append("\nfunction ").append(className);
88 for (FieldData v : jc.getFields()) {
90 out.append("\n this.fld_").
91 append(v.getName()).append(initField(v));
94 out.append("\n}\n\nfunction ").append(className).append("_proto() {");
95 out.append("\n if (").append(className).
96 append(".prototype.$instOf_").append(className).append(") {");
97 out.append("\n return new ").append(className).append(";");
99 for (FieldData v : jc.getFields()) {
101 generateStaticField(v);
104 // ClassName sc = jc.getSuperClass();
105 String sc = jc.getSuperClassName(); // with _
107 out.append("\n var p = ").append(className)
108 .append(".prototype = ").
109 append(sc.replace('/', '_')).append("_proto();");
111 out.append("\n var p = ").append(className).append(".prototype;");
113 for (MethodData m : jc.getMethods()) {
114 if (!m.getName().contains("<cinit>")) {
115 generateMethodReference("\n p.", m);
118 out.append("\n p.$instOf_").append(className).append(" = true;");
119 for (String superInterface : jc.getSuperInterfaces()) {
120 out.append("\n p.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
122 out.append("\n return new ").append(className).append(";");
124 out.append("\n").append(className).append("_proto();");
125 StringBuilder sb = new StringBuilder();
126 for (String init : toInitilize.toArray()) {
127 sb.append("\n").append(init).append("();");
129 return sb.toString();
131 private void generateStaticMethod(MethodData m, StringArray toInitilize) throws IOException {
132 if (javaScriptBody(m, true)) {
135 StringBuilder argsCnt = new StringBuilder();
136 final String mn = findMethodName(m, argsCnt);
137 out.append("\nfunction ").append(
139 ).append('_').append(mn);
140 if (mn.equals("classV")) {
141 toInitilize.add(className(jc) + '_' + mn);
145 for (int index = 0, i = 0; i < argsCnt.length(); i++) {
147 out.append("arg").append(String.valueOf(index));
149 final String desc = null;// XXX findDescriptor(args.get(i).getDescriptor());
150 if (argsCnt.charAt(i) == '1') {
156 out.append(") {").append("\n");
157 if (m.getCode() != null) {
158 int len = m.getMaxLocals();
159 for (int i = argsCnt.length(); i < len; i++) {
161 out.append("arg").append(String.valueOf(i)).append(";\n");
165 out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n");
170 private void generateMethodReference(String prefix, MethodData m) throws IOException {
171 final String name = findMethodName(m, new StringBuilder());
172 out.append(prefix).append(name).append(" = ")
173 .append(className(jc))
174 .append('_').append(name).append(";");
177 private void generateInstanceMethod(MethodData m) throws IOException {
178 if (javaScriptBody(m, false)) {
181 StringBuilder argsCnt = new StringBuilder();
182 out.append("\nfunction ").append(
184 ).append('_').append(findMethodName(m, argsCnt));
187 for (int index = 1, i = 0; i < argsCnt.length(); i++) {
189 out.append("arg").append(String.valueOf(index));
190 if (argsCnt.charAt(i) == '1') {
196 out.append(") {").append("\n");
197 if (m.getCode() != null) {
198 int len = m.getMaxLocals();
199 for (int i = argsCnt.length(); i < len; i++) {
201 out.append("arg").append(String.valueOf(i + 1)).append(";\n");
205 out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n");
210 private void produceCode(MethodData m) throws IOException {
211 final byte[] byteCodes = m.getCode();
212 final StackMapIterator stackMapIterator = m.createStackMapIterator();
213 final StackToVariableMapper mapper = new StackToVariableMapper();
215 // maxStack includes two stack positions for every pushed long / double
216 // so this might generate more stack variables than we need
217 final int maxStack = m.getMaxStack();
219 out.append("\n var ").append(mapper.constructVariableName(0));
220 for (int i = 1; i < maxStack; ++i) {
222 out.append(mapper.constructVariableName(i));
227 int lastStackFrame = -1;
229 out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
230 for (int i = 0; i < byteCodes.length; i++) {
232 stackMapIterator.advanceTo(i);
233 if (lastStackFrame != stackMapIterator.getFrameIndex()) {
234 lastStackFrame = stackMapIterator.getFrameIndex();
235 mapper.reset(stackMapIterator.getFrameStackItemsCount());
236 out.append(" case " + i).append(": ");
238 out.append(" /* " + i).append(" */ ");
240 final int c = readByte(byteCodes, i);
247 out.append(mapper.push()).append(" = arg0;");
254 out.append(mapper.push()).append(" = arg1;");
261 out.append(mapper.push()).append(" = arg2;");
268 out.append(mapper.push()).append(" = arg3;");
275 final int indx = readByte(byteCodes, ++i);
276 out.append(mapper.push())
286 final int indx = readByte(byteCodes, ++i);
287 out.append("arg" + indx)
289 .append(mapper.pop())
298 out.append("arg0 = ").append(mapper.pop()).append(';');
305 out.append("arg1 = ").append(mapper.pop()).append(';');
312 out.append("arg2 = ").append(mapper.pop()).append(';');
319 out.append("arg3 = ").append(mapper.pop()).append(';');
325 out.append(mapper.get(1)).append(" += ")
326 .append(mapper.pop()).append(';');
332 out.append(mapper.get(1)).append(" -= ")
333 .append(mapper.pop()).append(';');
339 out.append(mapper.get(1)).append(" *= ")
340 .append(mapper.pop()).append(';');
344 out.append(mapper.get(1))
345 .append(" = Math.floor(")
346 .append(mapper.get(1))
348 .append(mapper.pop())
353 out.append(mapper.get(1)).append(" /= ")
354 .append(mapper.pop()).append(';');
360 out.append(mapper.get(1)).append(" %= ")
361 .append(mapper.pop()).append(';');
365 out.append(mapper.get(1)).append(" &= ")
366 .append(mapper.pop()).append(';');
370 out.append(mapper.get(1)).append(" |= ")
371 .append(mapper.pop()).append(';');
375 out.append(mapper.get(1)).append(" ^= ")
376 .append(mapper.pop()).append(';');
382 out.append(mapper.get(0)).append(" = -")
383 .append(mapper.get(0)).append(';');
387 out.append(mapper.get(1)).append(" <<= ")
388 .append(mapper.pop()).append(';');
392 out.append(mapper.get(1)).append(" >>= ")
393 .append(mapper.pop()).append(';');
397 out.append(mapper.get(1)).append(" >>>= ")
398 .append(mapper.pop()).append(';');
401 final int varIndx = readByte(byteCodes, ++i);
402 final int incrBy = byteCodes[++i];
404 out.append("arg" + varIndx).append("++;");
406 out.append("arg" + varIndx).append(" += " + incrBy).append(";");
411 out.append("return;");
418 out.append("return ").append(mapper.pop()).append(';');
429 out.append("/* number conversion */");
435 out.append(mapper.get(0))
436 .append(" = Math.floor(")
437 .append(mapper.get(0))
443 out.append("/* number conversion */");
445 case opc_aconst_null:
446 out.append(mapper.push()).append(" = null;");
449 out.append(mapper.push()).append(" = -1;");
455 out.append(mapper.push()).append(" = 0;");
461 out.append(mapper.push()).append(" = 1;");
465 out.append(mapper.push()).append(" = 2;");
468 out.append(mapper.push()).append(" = 3;");
471 out.append(mapper.push()).append(" = 4;");
474 out.append(mapper.push()).append(" = 5;");
477 int indx = readByte(byteCodes, ++i);
478 String v = encodeConstant(indx);
479 out.append(mapper.push())
487 int indx = readIntArg(byteCodes, i);
489 String v = encodeConstant(indx);
490 out.append(mapper.push())
501 out.append(mapper.get(1))
503 .append(mapper.get(1))
505 .append(mapper.get(0))
506 .append(") ? 0 : ((")
507 .append(mapper.get(1))
509 .append(mapper.get(0))
510 .append(") ? -1 : 1);");
516 i = generateIf(byteCodes, i, mapper, "===");
519 i = generateIf(byteCodes, i, mapper, "!=");
521 case opc_if_icmpeq: {
522 i = generateIf(byteCodes, i, mapper, "==");
526 int indx = i + readIntArg(byteCodes, i);
527 out.append("if (").append(mapper.pop())
528 .append(" == 0) { gt = " + indx);
529 out.append("; continue; }");
534 int indx = i + readIntArg(byteCodes, i);
535 out.append("if (").append(mapper.pop())
536 .append(" != 0) { gt = " + indx);
537 out.append("; continue; }");
542 int indx = i + readIntArg(byteCodes, i);
543 out.append("if (").append(mapper.pop())
544 .append(" < 0) { gt = " + indx);
545 out.append("; continue; }");
550 int indx = i + readIntArg(byteCodes, i);
551 out.append("if (").append(mapper.pop())
552 .append(" <= 0) { gt = " + indx);
553 out.append("; continue; }");
558 int indx = i + readIntArg(byteCodes, i);
559 out.append("if (").append(mapper.pop())
560 .append(" > 0) { gt = " + indx);
561 out.append("; continue; }");
566 int indx = i + readIntArg(byteCodes, i);
567 out.append("if (").append(mapper.pop())
568 .append(" >= 0) { gt = " + indx);
569 out.append("; continue; }");
573 case opc_ifnonnull: {
574 int indx = i + readIntArg(byteCodes, i);
575 out.append("if (").append(mapper.pop())
576 .append(" !== null) { gt = " + indx);
577 out.append("; continue; }");
582 int indx = i + readIntArg(byteCodes, i);
583 out.append("if (").append(mapper.pop())
584 .append(" === null) { gt = " + indx);
585 out.append("; continue; }");
590 i = generateIf(byteCodes, i, mapper, "!=");
593 i = generateIf(byteCodes, i, mapper, "<");
596 i = generateIf(byteCodes, i, mapper, "<=");
599 i = generateIf(byteCodes, i, mapper, ">");
602 i = generateIf(byteCodes, i, mapper, ">=");
605 int indx = i + readIntArg(byteCodes, i);
606 out.append("gt = " + indx).append("; continue;");
610 case opc_lookupswitch: {
611 int table = i / 4 * 4 + 4;
612 int dflt = i + readInt4(byteCodes, table);
614 int n = readInt4(byteCodes, table);
616 out.append("switch (").append(mapper.pop()).append(") {\n");
618 int cnstnt = readInt4(byteCodes, table);
620 int offset = i + readInt4(byteCodes, table);
622 out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
624 out.append(" default: gt = " + dflt).append("; continue;\n}");
628 case opc_tableswitch: {
629 int table = i / 4 * 4 + 4;
630 int dflt = i + readInt4(byteCodes, table);
632 int low = readInt4(byteCodes, table);
634 int high = readInt4(byteCodes, table);
636 out.append("switch (").append(mapper.pop()).append(") {\n");
637 while (low <= high) {
638 int offset = i + readInt4(byteCodes, table);
640 out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
643 out.append(" default: gt = " + dflt).append("; continue;\n}");
647 case opc_invokeinterface: {
648 i = invokeVirtualMethod(byteCodes, i, mapper) + 2;
651 case opc_invokevirtual:
652 i = invokeVirtualMethod(byteCodes, i, mapper);
654 case opc_invokespecial:
655 i = invokeStaticMethod(byteCodes, i, mapper, false);
657 case opc_invokestatic:
658 i = invokeStaticMethod(byteCodes, i, mapper, true);
661 int indx = readIntArg(byteCodes, i);
662 String ci = jc.getClassName(indx);
663 out.append(mapper.push()).append(" = ");
664 out.append("new ").append(ci.replace('/','_'));
671 ++i; // skip type of array
672 out.append(mapper.get(0))
673 .append(" = new Array(")
674 .append(mapper.get(0))
675 .append(").fillNulls();");
678 case opc_anewarray: {
679 i += 2; // skip type of array
680 out.append(mapper.get(0))
681 .append(" = new Array(")
682 .append(mapper.get(0))
683 .append(").fillNulls();");
686 case opc_multianewarray: {
688 int dim = readByte(byteCodes, ++i);
689 out.append("{ var a0 = new Array(").append(mapper.pop())
690 .append(").fillNulls();");
691 for (int d = 1; d < dim; d++) {
692 out.append("\n var l" + d).append(" = ")
693 .append(mapper.pop()).append(';');
694 out.append("\n for (var i" + d).append (" = 0; i" + d).
695 append(" < a" + (d - 1)).
696 append(".length; i" + d).append("++) {");
697 out.append("\n var a" + d).
698 append (" = new Array(l" + d).append(").fillNulls();");
699 out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d).
702 for (int d = 1; d < dim; d++) {
705 out.append("\n").append(mapper.push()).append(" = a0; }");
708 case opc_arraylength:
709 out.append(mapper.get(0)).append(" = ")
710 .append(mapper.get(0)).append(".length;");
720 out.append(mapper.get(2))
721 .append('[').append(mapper.get(1)).append(']')
723 .append(mapper.get(0))
736 out.append(mapper.get(1))
738 .append(mapper.get(1))
739 .append('[').append(mapper.pop()).append("];");
745 out.append("/* pop */");
748 out.append(mapper.push()).append(" = ")
749 .append(mapper.get(1)).append(';');
753 out.append(mapper.push()).append(" = ")
754 .append(mapper.get(1)).append("; ");
755 out.append(mapper.get(1)).append(" = ")
756 .append(mapper.get(2)).append("; ");
757 out.append(mapper.get(2)).append(" = ")
758 .append(mapper.get(0)).append("; ");
763 out.append(mapper.push()).append(" = ")
764 .append(mapper.get(1)).append("; ");
765 out.append(mapper.get(1)).append(" = ")
766 .append(mapper.get(2)).append("; ");
767 out.append(mapper.get(2)).append(" = ")
768 .append(mapper.get(3)).append("; ");
769 out.append(mapper.get(3)).append(" = ")
770 .append(mapper.get(0)).append("; ");
774 out.append(mapper.push()).append(" = ")
775 .append(Integer.toString(byteCodes[++i])).append(';');
778 out.append(mapper.push()).append(" = ")
779 .append(Integer.toString(readIntArg(byteCodes, i)))
784 int indx = readIntArg(byteCodes, i);
785 String[] fi = jc.getFieldInfoName(indx);
786 out.append(mapper.get(0)).append(" = ")
787 .append(mapper.get(0)).append(".fld_")
788 .append(fi[1]).append(';');
792 case opc_getstatic: {
793 int indx = readIntArg(byteCodes, i);
794 String[] fi = jc.getFieldInfoName(indx);
795 out.append(mapper.push()).append(" = ")
796 .append(fi[0].replace('/', '_'))
797 .append('.').append(fi[1]).append(';');
802 case opc_putstatic: {
803 int indx = readIntArg(byteCodes, i);
804 String[] fi = jc.getFieldInfoName(indx);
805 out.append(fi[0].replace('/', '_'));
806 out.append('.').append(fi[1]).append(" = ")
807 .append(mapper.pop()).append(';');
813 int indx = readIntArg(byteCodes, i);
814 String[] fi = jc.getFieldInfoName(indx);
815 out.append(mapper.get(1)).append(".fld_").append(fi[1])
817 .append(mapper.get(0)).append(';');
822 case opc_checkcast: {
823 int indx = readIntArg(byteCodes, i);
824 final String type = jc.getClassName(indx);
825 if (!type.startsWith("[")) {
826 // no way to check arrays right now
827 out.append("if (").append(mapper.get(0))
828 .append(".$instOf_").append(type.replace('/', '_'))
829 .append(" != 1) throw {};"); // XXX proper exception
834 case opc_instanceof: {
835 int indx = readIntArg(byteCodes, i);
836 final String type = jc.getClassName(indx);
837 out.append(mapper.get(0)).append(" = ")
838 .append(mapper.get(0)).append(".$instOf_")
839 .append(type.replace('/', '_'))
840 .append(" ? 1 : 0;");
846 out.append(mapper.bottom()).append(" = ")
847 .append(mapper.top()).append("; ");
848 out.append("throw ").append(mapper.bottom()).append("; ");
855 case opc_monitorenter: {
856 out.append("/* monitor enter */");
861 case opc_monitorexit: {
862 out.append("/* monitor exit */");
868 out.append("throw 'unknown bytecode " + c + "';");
873 for (int j = prev; j <= i; j++) {
875 final int cc = readByte(byteCodes, j);
876 out.append(Integer.toString(cc));
882 if (mapper.getMaxStackSize() > maxStack) {
883 throw new IllegalStateException("Incorrect stack usage");
887 private int generateIf(byte[] byteCodes, int i, final StackToVariableMapper mapper, final String test) throws IOException {
888 int indx = i + readIntArg(byteCodes, i);
889 out.append("if (").append(mapper.get(1))
890 .append(' ').append(test).append(' ')
891 .append(mapper.get(0)).append(") { gt = " + indx)
892 .append("; continue; }");
897 private int readIntArg(byte[] byteCodes, int offsetInstruction) {
898 final int indxHi = byteCodes[offsetInstruction + 1] << 8;
899 final int indxLo = byteCodes[offsetInstruction + 2];
900 return (indxHi & 0xffffff00) | (indxLo & 0xff);
902 private int readInt4(byte[] byteCodes, int offsetInstruction) {
903 final int d = byteCodes[offsetInstruction + 0] << 24;
904 final int c = byteCodes[offsetInstruction + 1] << 16;
905 final int b = byteCodes[offsetInstruction + 2] << 8;
906 final int a = byteCodes[offsetInstruction + 3];
907 return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
909 private int readByte(byte[] byteCodes, int offsetInstruction) {
910 return byteCodes[offsetInstruction] & 0xff;
913 private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) {
915 Boolean count = null;
916 boolean array = false;
917 int firstPos = sig.length();
918 while (i < descriptor.length()) {
919 char ch = descriptor.charAt(i++);
943 if (ch == 'J' || ch == 'D') {
949 hasReturnType[0] = true;
950 sig.insert(firstPos, ch);
952 sig.insert(firstPos, 'A');
959 hasReturnType[0] = false;
960 sig.insert(firstPos, 'V');
963 int next = descriptor.indexOf(';', i);
969 sig.append(descriptor.substring(i, next).replace('/', '_'));
972 sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_'));
973 sig.insert(firstPos, ch);
975 sig.insert(firstPos, 'A');
977 hasReturnType[0] = true;
985 break; // invalid character
990 private void generateStaticField(FieldData v) throws IOException {
992 .append(className(jc))
993 .append('.').append(v.getName()).append(initField(v));
996 private String findMethodName(MethodData m, StringBuilder cnt) {
997 StringBuilder name = new StringBuilder();
998 if ("<init>".equals(m.getName())) { // NOI18N
999 name.append("cons"); // NOI18N
1000 } else if ("<clinit>".equals(m.getName())) { // NOI18N
1001 name.append("class"); // NOI18N
1003 name.append(m.getName());
1006 boolean hasReturn[] = { false };
1007 countArgs(findDescriptor(m.getInternalSig()), hasReturn, name, cnt);
1008 return name.toString();
1011 private String findMethodName(String[] mi, StringBuilder cnt, boolean[] hasReturn) {
1012 StringBuilder name = new StringBuilder();
1013 String descr = mi[2];//mi.getDescriptor();
1015 if ("<init>".equals(nm)) { // NOI18N
1016 name.append("cons"); // NOI18N
1020 countArgs(findDescriptor(descr), hasReturn, name, cnt);
1021 return name.toString();
1024 private int invokeStaticMethod(byte[] byteCodes, int i, final StackToVariableMapper mapper, boolean isStatic)
1025 throws IOException {
1026 int methodIndex = readIntArg(byteCodes, i);
1027 String[] mi = jc.getFieldInfoName(methodIndex);
1028 boolean[] hasReturn = { false };
1029 StringBuilder cnt = new StringBuilder();
1030 String mn = findMethodName(mi, cnt, hasReturn);
1032 final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
1035 out.append((numArguments > 0) ? mapper.get(numArguments - 1)
1036 : mapper.push()).append(" = ");
1039 final String in = mi[0];
1040 out.append(in.replace('/', '_'));
1041 out.append(".prototype.");
1044 if (numArguments > 0) {
1045 out.append(mapper.get(numArguments - 1));
1046 for (int j = numArguments - 2; j >= 0; --j) {
1048 out.append(mapper.get(j));
1052 if (numArguments > 0) {
1053 mapper.pop(hasReturn[0] ? numArguments - 1 : numArguments);
1059 private int invokeVirtualMethod(byte[] byteCodes, int i, final StackToVariableMapper mapper)
1060 throws IOException {
1061 int methodIndex = readIntArg(byteCodes, i);
1062 String[] mi = jc.getFieldInfoName(methodIndex);
1063 boolean[] hasReturn = { false };
1064 StringBuilder cnt = new StringBuilder();
1065 String mn = findMethodName(mi, cnt, hasReturn);
1067 final int numArguments = cnt.length();
1070 out.append(mapper.get(numArguments)).append(" = ");
1073 out.append(mapper.get(numArguments)).append('.');
1076 out.append(mapper.get(numArguments));
1077 for (int j = numArguments - 1; j >= 0; --j) {
1079 out.append(mapper.get(j));
1082 mapper.pop(hasReturn[0] ? numArguments : numArguments + 1);
1087 private void addReference(String cn) throws IOException {
1088 if (requireReference(cn)) {
1089 out.append(" /* needs ").append(cn).append(" */");
1093 private void outType(String d, StringBuilder out) {
1095 while (d.charAt(0) == '[') {
1099 if (d.charAt(0) == 'L') {
1100 assert d.charAt(d.length() - 1) == ';';
1101 out.append(d.replace('/', '_').substring(0, d.length() - 1));
1107 private String encodeConstant(int entryIndex) {
1108 String s = jc.stringValue(entryIndex, true);
1112 private String findDescriptor(String d) {
1113 return d.replace('[', 'A');
1116 private boolean javaScriptBody(MethodData m, boolean isStatic) throws IOException {
1117 byte[] arr = m.findAnnotationData(true);
1121 final String jvmType = "L" + JavaScriptBody.class.getName().replace('.', '/') + ";";
1122 class P extends AnnotationParser {
1124 String[] args = new String[30];
1128 protected void visitAttr(String type, String attr, String value) {
1129 if (type.equals(jvmType)) {
1130 if ("body".equals(attr)) {
1132 } else if ("args".equals(attr)) {
1133 args[cnt++] = value;
1135 throw new IllegalArgumentException(attr);
1142 if (p.body == null) {
1145 StringBuilder cnt = new StringBuilder();
1146 out.append("\nfunction ").append(className(jc)).append('_').
1147 append(findMethodName(m, cnt));
1152 out.append(p.args[0]);
1159 for (int i = 0; i < cnt.length(); i++) {
1161 out.append(p.args[index]);
1165 out.append(") {").append("\n");
1167 out.append("\n}\n");
1170 private static String className(ClassData jc) {
1171 //return jc.getName().getInternalName().replace('/', '_');
1172 return jc.getClassName().replace('/', '_');
1175 private static String[] findAnnotation(
1176 byte[] arr, ClassData cd, final String className,
1177 final String... attrNames
1178 ) throws IOException {
1182 final String[] values = new String[attrNames.length];
1183 final boolean[] found = { false };
1184 final String jvmType = "L" + className.replace('.', '/') + ";";
1185 AnnotationParser ap = new AnnotationParser() {
1187 protected void visitAttr(String type, String attr, String value) {
1188 if (type.equals(jvmType)) {
1190 for (int i = 0; i < attrNames.length; i++) {
1191 if (attrNames[i].equals(attr)) {
1200 return found[0] ? values : null;
1203 private CharSequence initField(FieldData v) {
1204 final String is = v.getInternalSig();
1205 if (is.length() == 1) {
1206 switch (is.charAt(0)) {
1212 case 'I': return " = 0;";
1214 case 'D': return " = 0.0;";
1216 throw new IllegalStateException(is);