vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
author tzezula
Sat, 08 Dec 2012 08:19:46 +0100
branchexceptions
changeset 285 c8be2d837788
parent 106 346633cd13d6
child 287 6f696a0ef12f
permissions -rw-r--r--
Original version of exception handling.
jaroslav@106
     1
/**
jaroslav@106
     2
 * Back 2 Browser Bytecode Translator
jaroslav@106
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@106
     4
 *
jaroslav@106
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@106
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@106
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@106
     8
 *
jaroslav@106
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@106
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@106
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@106
    12
 * GNU General Public License for more details.
jaroslav@106
    13
 *
jaroslav@106
    14
 * You should have received a copy of the GNU General Public License
jaroslav@106
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@106
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@106
    17
 */
jaroslav@0
    18
/*
jaroslav@0
    19
Java 4 Browser Bytecode Translator
jaroslav@0
    20
Copyright (C) 2012-2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@0
    21
jaroslav@0
    22
This program is free software: you can redistribute it and/or modify
jaroslav@0
    23
it under the terms of the GNU General Public License as published by
jaroslav@0
    24
the Free Software Foundation, version 2 of the License.
jaroslav@0
    25
jaroslav@0
    26
This program is distributed in the hope that it will be useful,
jaroslav@0
    27
but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@0
    28
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@0
    29
GNU General Public License for more details.
jaroslav@0
    30
jaroslav@0
    31
You should have received a copy of the GNU General Public License
jaroslav@0
    32
along with this program. Look for COPYING file in the top folder.
jaroslav@0
    33
If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@0
    34
*/
jaroslav@22
    35
package org.apidesign.vm4brwsr;
jaroslav@0
    36
jaroslav@0
    37
import java.io.IOException;
jaroslav@0
    38
import java.io.InputStream;
tzezula@285
    39
import java.util.ArrayDeque;
jaroslav@21
    40
import java.util.ArrayList;
jaroslav@18
    41
import java.util.Collection;
tzezula@285
    42
import java.util.Deque;
tzezula@285
    43
import java.util.HashMap;
jaroslav@0
    44
import java.util.List;
tzezula@285
    45
import java.util.Map;
jaroslav@91
    46
import org.apidesign.bck2brwsr.core.ExtraJavaScript;
jaroslav@94
    47
import org.apidesign.bck2brwsr.core.JavaScriptBody;
jaroslav@91
    48
import org.netbeans.modules.classfile.Annotation;
jaroslav@91
    49
import org.netbeans.modules.classfile.AnnotationComponent;
jaroslav@94
    50
import org.netbeans.modules.classfile.ArrayElementValue;
jaroslav@2
    51
import static org.netbeans.modules.classfile.ByteCodes.*;
jaroslav@8
    52
import org.netbeans.modules.classfile.CPClassInfo;
jaroslav@8
    53
import org.netbeans.modules.classfile.CPEntry;
jaroslav@8
    54
import org.netbeans.modules.classfile.CPFieldInfo;
jaroslav@4
    55
import org.netbeans.modules.classfile.CPMethodInfo;
jaroslav@21
    56
import org.netbeans.modules.classfile.CPStringInfo;
jaroslav@0
    57
import org.netbeans.modules.classfile.ClassFile;
jaroslav@13
    58
import org.netbeans.modules.classfile.ClassName;
jaroslav@0
    59
import org.netbeans.modules.classfile.Code;
jaroslav@91
    60
import org.netbeans.modules.classfile.ElementValue;
tzezula@285
    61
import org.netbeans.modules.classfile.ExceptionTableEntry;
jaroslav@0
    62
import org.netbeans.modules.classfile.Method;
jaroslav@0
    63
import org.netbeans.modules.classfile.Parameter;
jaroslav@91
    64
import org.netbeans.modules.classfile.PrimitiveElementValue;
jaroslav@9
    65
import org.netbeans.modules.classfile.Variable;
jaroslav@0
    66
jaroslav@0
    67
/** Translator of the code inside class files to JavaScript.
jaroslav@0
    68
 *
jaroslav@0
    69
 * @author Jaroslav Tulach <jtulach@netbeans.org>
jaroslav@0
    70
 */
jaroslav@0
    71
public final class ByteCodeToJavaScript {
jaroslav@0
    72
    private final ClassFile jc;
jaroslav@0
    73
    private final Appendable out;
jaroslav@18
    74
    private final Collection<? super String> references;
jaroslav@0
    75
jaroslav@18
    76
    private ByteCodeToJavaScript(
jaroslav@18
    77
        ClassFile jc, Appendable out, Collection<? super String> references
jaroslav@18
    78
    ) {
jaroslav@0
    79
        this.jc = jc;
jaroslav@0
    80
        this.out = out;
jaroslav@18
    81
        this.references = references;
jaroslav@0
    82
    }
jaroslav@18
    83
jaroslav@18
    84
    /**
jaroslav@18
    85
     * Converts a given class file to a JavaScript version.
jaroslav@18
    86
     *
jaroslav@0
    87
     * @param classFile input stream with code of the .class file
jaroslav@0
    88
     * @param out a {@link StringBuilder} or similar to generate the output to
jaroslav@18
    89
     * @param references a write only collection where the system adds list of
jaroslav@18
    90
     *   other classes that were referenced and should be loaded in order the
jaroslav@18
    91
     *   generated JavaScript code works properly. The names are in internal 
jaroslav@18
    92
     *   JVM form so String is <code>java/lang/String</code>. Can be <code>null</code>
jaroslav@18
    93
     *   if one is not interested in knowing references
jaroslav@91
    94
     * @param scripts write only collection with names of resources to read
jaroslav@97
    95
     * @return the initialization code for this class, if any. Otherwise <code>null</code>
jaroslav@91
    96
     * 
jaroslav@0
    97
     * @throws IOException if something goes wrong during read or write or translating
jaroslav@0
    98
     */
jaroslav@18
    99
    
jaroslav@97
   100
    public static String compile(
jaroslav@18
   101
        InputStream classFile, Appendable out,
jaroslav@91
   102
        Collection<? super String> references,
jaroslav@91
   103
        Collection<? super String> scripts
jaroslav@18
   104
    ) throws IOException {
jaroslav@0
   105
        ClassFile jc = new ClassFile(classFile, true);
jaroslav@91
   106
        final ClassName extraAnn = ClassName.getClassName(ExtraJavaScript.class.getName().replace('.', '/'));
jaroslav@91
   107
        Annotation a = jc.getAnnotation(extraAnn);
jaroslav@91
   108
        if (a != null) {
jaroslav@91
   109
            final ElementValue annVal = a.getComponent("resource").getValue();
jaroslav@91
   110
            String res = ((PrimitiveElementValue)annVal).getValue().getValue().toString();
jaroslav@91
   111
            scripts.add(res);
jaroslav@91
   112
            final AnnotationComponent process = a.getComponent("processByteCode");
jaroslav@93
   113
            if (process != null && "const=0".equals(process.getValue().toString())) {
jaroslav@97
   114
                return null;
jaroslav@91
   115
            }
jaroslav@91
   116
        }
jaroslav@91
   117
        
jaroslav@18
   118
        ByteCodeToJavaScript compiler = new ByteCodeToJavaScript(
jaroslav@18
   119
            jc, out, references
jaroslav@18
   120
        );
jaroslav@21
   121
        List<String> toInitilize = new ArrayList<String>();
jaroslav@0
   122
        for (Method m : jc.getMethods()) {
jaroslav@0
   123
            if (m.isStatic()) {
jaroslav@21
   124
                compiler.generateStaticMethod(m, toInitilize);
jaroslav@10
   125
            } else {
jaroslav@10
   126
                compiler.generateInstanceMethod(m);
jaroslav@0
   127
            }
jaroslav@0
   128
        }
jaroslav@9
   129
        for (Variable v : jc.getVariables()) {
jaroslav@9
   130
            if (v.isStatic()) {
jaroslav@9
   131
                compiler.generateStaticField(v);
jaroslav@9
   132
            }
jaroslav@9
   133
        }
jaroslav@10
   134
        
jaroslav@18
   135
        final String className = jc.getName().getInternalName().replace('/', '_');
jaroslav@13
   136
        out.append("\nfunction ").append(className);
jaroslav@10
   137
        out.append("() {");
jaroslav@10
   138
        for (Variable v : jc.getVariables()) {
jaroslav@10
   139
            if (!v.isStatic()) {
jaroslav@10
   140
                out.append("\n  this." + v.getName() + " = 0;");
jaroslav@10
   141
            }
jaroslav@10
   142
        }
jaroslav@98
   143
        out.append("\n}\n\nfunction ").append(className).append("_proto() {");
jaroslav@98
   144
        out.append("\n  if (").append(className).
jaroslav@98
   145
            append(".prototype.$instOf_").append(className).append(") {");
jaroslav@98
   146
        out.append("\n    return ").append(className).append(".prototype;");
jaroslav@98
   147
        out.append("\n  }");
jaroslav@13
   148
        ClassName sc = jc.getSuperClass();
jaroslav@13
   149
        if (sc != null) {
jaroslav@98
   150
            out.append("\n  ").append(sc.getInternalName().replace('/', '_')).append("_proto();");
jaroslav@98
   151
            out.append("\n  ").append(className)
jaroslav@39
   152
               .append(".prototype = new ").append(sc.getInternalName().replace('/', '_')).append(';');
jaroslav@13
   153
        }
jaroslav@38
   154
        for (Method m : jc.getMethods()) {
jaroslav@102
   155
            if (!m.getName().contains("<init>") && !m.getName().contains("<cinit>")) {
jaroslav@98
   156
                compiler.generateMethodReference("\n  " + className + ".prototype.", m);
jaroslav@38
   157
            }
jaroslav@38
   158
        }
jaroslav@98
   159
        out.append("\n  " + className + ".prototype.$instOf_").append(className).append(" = true;");
jaroslav@40
   160
        for (ClassName superInterface : jc.getInterfaces()) {
jaroslav@98
   161
            out.append("\n  " + className + ".prototype.$instOf_").append(superInterface.getInternalName().replace('/', '_')).append(" = true;");
jaroslav@40
   162
        }
jaroslav@98
   163
        out.append("\n  return ").append(className).append(".prototype;");
jaroslav@98
   164
        out.append("\n}");
jaroslav@98
   165
        out.append("\n").append(className).append("_proto();");
jaroslav@97
   166
        StringBuilder sb = new StringBuilder();
jaroslav@21
   167
        for (String init : toInitilize) {
jaroslav@97
   168
            sb.append("\n").append(init).append("();");
jaroslav@21
   169
        }
jaroslav@97
   170
        return sb.toString();
jaroslav@0
   171
    }
jaroslav@21
   172
    private void generateStaticMethod(Method m, List<String> toInitilize) throws IOException {
jaroslav@94
   173
        if (javaScriptBody(m, true)) {
jaroslav@94
   174
            return;
jaroslav@94
   175
        }
jaroslav@21
   176
        final String mn = findMethodName(m);
jaroslav@1
   177
        out.append("\nfunction ").append(
jaroslav@18
   178
            jc.getName().getInternalName().replace('/', '_')
jaroslav@21
   179
        ).append('_').append(mn);
jaroslav@21
   180
        if (mn.equals("classV")) {
jaroslav@21
   181
            toInitilize.add(jc.getName().getInternalName().replace('/', '_') + '_' + mn);
jaroslav@21
   182
        }
jaroslav@0
   183
        out.append('(');
jaroslav@0
   184
        String space = "";
jaroslav@10
   185
        List<Parameter> args = m.getParameters();
jaroslav@2
   186
        for (int index = 0, i = 0; i < args.size(); i++) {
jaroslav@0
   187
            out.append(space);
jaroslav@2
   188
            out.append("arg").append(String.valueOf(index));
jaroslav@0
   189
            space = ",";
jaroslav@32
   190
            final String desc = findDescriptor(args.get(i).getDescriptor());
jaroslav@3
   191
            if ("D".equals(desc) || "J".equals(desc)) {
jaroslav@2
   192
                index += 2;
jaroslav@2
   193
            } else {
jaroslav@2
   194
                index++;
jaroslav@2
   195
            }
jaroslav@0
   196
        }
jaroslav@5
   197
        out.append(") {").append("\n");
jaroslav@0
   198
        final Code code = m.getCode();
jaroslav@18
   199
        if (code != null) {
jaroslav@18
   200
            int len = code.getMaxLocals();
jaroslav@18
   201
            for (int index = args.size(), i = args.size(); i < len; i++) {
jaroslav@18
   202
                out.append("  var ");
jaroslav@18
   203
                out.append("arg").append(String.valueOf(i)).append(";\n");
jaroslav@18
   204
            }
jaroslav@21
   205
            out.append("  var stack = new Array();\n");
tzezula@285
   206
            produceCode(code.getByteCodes(), code.getExceptionTable());
jaroslav@18
   207
        } else {
jaroslav@18
   208
            out.append("  /* no code found for ").append(m.getTypeSignature()).append(" */\n");
jaroslav@0
   209
        }
jaroslav@10
   210
        out.append("}");
jaroslav@10
   211
    }
jaroslav@10
   212
    
jaroslav@38
   213
    private void generateMethodReference(String prefix, Method m) throws IOException {
jaroslav@12
   214
        final String name = findMethodName(m);
jaroslav@38
   215
        out.append(prefix).append(name).append(" = ")
jaroslav@18
   216
           .append(jc.getName().getInternalName().replace('/', '_'))
jaroslav@12
   217
           .append('_').append(name).append(";");
jaroslav@12
   218
    }
jaroslav@12
   219
    
jaroslav@10
   220
    private void generateInstanceMethod(Method m) throws IOException {
jaroslav@94
   221
        if (javaScriptBody(m, false)) {
jaroslav@94
   222
            return;
jaroslav@94
   223
        }
jaroslav@10
   224
        out.append("\nfunction ").append(
jaroslav@18
   225
            jc.getName().getInternalName().replace('/', '_')
jaroslav@10
   226
        ).append('_').append(findMethodName(m));
jaroslav@10
   227
        out.append("(arg0");
jaroslav@10
   228
        String space = ",";
jaroslav@10
   229
        List<Parameter> args = m.getParameters();
jaroslav@10
   230
        for (int index = 1, i = 0; i < args.size(); i++) {
jaroslav@10
   231
            out.append(space);
jaroslav@10
   232
            out.append("arg").append(String.valueOf(index));
jaroslav@32
   233
            final String desc = findDescriptor(args.get(i).getDescriptor());
jaroslav@10
   234
            if ("D".equals(desc) || "J".equals(desc)) {
jaroslav@10
   235
                index += 2;
jaroslav@10
   236
            } else {
jaroslav@10
   237
                index++;
jaroslav@10
   238
            }
jaroslav@10
   239
        }
jaroslav@10
   240
        out.append(") {").append("\n");
jaroslav@10
   241
        final Code code = m.getCode();
jaroslav@18
   242
        if (code != null) {
jaroslav@18
   243
            int len = code.getMaxLocals();
jaroslav@18
   244
            for (int index = args.size(), i = args.size(); i < len; i++) {
jaroslav@18
   245
                out.append("  var ");
jaroslav@18
   246
                out.append("arg").append(String.valueOf(i + 1)).append(";\n");
jaroslav@18
   247
            }
jaroslav@96
   248
            out.append(";\n  var stack = new Array();\n");
tzezula@285
   249
            produceCode(code.getByteCodes(), code.getExceptionTable());
jaroslav@18
   250
        } else {
jaroslav@18
   251
            out.append("  /* no code found for ").append(m.getTypeSignature()).append(" */\n");
jaroslav@10
   252
        }
jaroslav@0
   253
        out.append("}");
jaroslav@0
   254
    }
jaroslav@0
   255
tzezula@285
   256
    private void produceCode(byte[] byteCodes, ExceptionTableEntry[] exceptionTable) throws IOException {
tzezula@285
   257
        final Map<Integer, ExceptionTableEntry> exStart = new HashMap<Integer, ExceptionTableEntry>();
tzezula@285
   258
        final Map<Integer, ExceptionTableEntry> exStop = new HashMap<Integer, ExceptionTableEntry>();
tzezula@285
   259
        for (ExceptionTableEntry e : exceptionTable) {
tzezula@285
   260
            exStart.put(e.getStartPC(), e);
tzezula@285
   261
            exStop.put(e.getEndPC(), e);
tzezula@285
   262
        }
tzezula@285
   263
        final Deque<ExceptionTableEntry> current = new ArrayDeque<ExceptionTableEntry>();
jaroslav@10
   264
        out.append("\n  var gt = 0;\n  for(;;) switch(gt) {\n");
jaroslav@0
   265
        for (int i = 0; i < byteCodes.length; i++) {
tzezula@285
   266
            {
tzezula@285
   267
                ExceptionTableEntry e = exStart.get(i);
tzezula@285
   268
                if (e != null) {
tzezula@285
   269
                    current.addFirst(e);
tzezula@285
   270
                }
tzezula@285
   271
                e = exStop.get(i);
tzezula@285
   272
                if (e != null) {
tzezula@285
   273
                    current.remove(e);
tzezula@285
   274
                }
tzezula@285
   275
            }
jaroslav@0
   276
            int prev = i;
jaroslav@10
   277
            out.append("    case " + i).append(": ");
tzezula@285
   278
            if (!current.isEmpty()) {
tzezula@285
   279
                out.append("try {");
tzezula@285
   280
            }
jaroslav@0
   281
            final int c = (byteCodes[i] + 256) % 256;
jaroslav@0
   282
            switch (c) {
jaroslav@2
   283
                case bc_aload_0:
jaroslav@2
   284
                case bc_iload_0:
jaroslav@2
   285
                case bc_lload_0:
jaroslav@2
   286
                case bc_fload_0:
jaroslav@2
   287
                case bc_dload_0:
jaroslav@0
   288
                    out.append("stack.push(arg0);");
jaroslav@0
   289
                    break;
jaroslav@2
   290
                case bc_aload_1:
jaroslav@2
   291
                case bc_iload_1:
jaroslav@2
   292
                case bc_lload_1:
jaroslav@2
   293
                case bc_fload_1:
jaroslav@2
   294
                case bc_dload_1:
jaroslav@0
   295
                    out.append("stack.push(arg1);");
jaroslav@0
   296
                    break;
jaroslav@2
   297
                case bc_aload_2:
jaroslav@2
   298
                case bc_iload_2:
jaroslav@2
   299
                case bc_lload_2:
jaroslav@2
   300
                case bc_fload_2:
jaroslav@2
   301
                case bc_dload_2:
jaroslav@2
   302
                    out.append("stack.push(arg2);");
jaroslav@2
   303
                    break;
jaroslav@3
   304
                case bc_aload_3:
jaroslav@3
   305
                case bc_iload_3:
jaroslav@3
   306
                case bc_lload_3:
jaroslav@3
   307
                case bc_fload_3:
jaroslav@3
   308
                case bc_dload_3:
jaroslav@3
   309
                    out.append("stack.push(arg3);");
jaroslav@3
   310
                    break;
jaroslav@3
   311
                case bc_iload:
jaroslav@3
   312
                case bc_lload:
jaroslav@3
   313
                case bc_fload:
jaroslav@3
   314
                case bc_dload:
jaroslav@3
   315
                case bc_aload: {
jaroslav@3
   316
                    final int indx = (byteCodes[++i] + 256) % 256;
jaroslav@3
   317
                    out.append("stack.push(arg").append(indx + ");");
jaroslav@3
   318
                    break;
jaroslav@3
   319
                }
jaroslav@31
   320
                case bc_istore:
jaroslav@31
   321
                case bc_lstore:
jaroslav@31
   322
                case bc_fstore:
jaroslav@31
   323
                case bc_dstore:
jaroslav@31
   324
                case bc_astore: {
jaroslav@31
   325
                    final int indx = (byteCodes[++i] + 256) % 256;
jaroslav@31
   326
                    out.append("arg" + indx).append(" = stack.pop()");
jaroslav@31
   327
                    break;
jaroslav@31
   328
                }
jaroslav@8
   329
                case bc_astore_0:
jaroslav@5
   330
                case bc_istore_0:
jaroslav@5
   331
                case bc_lstore_0:
jaroslav@5
   332
                case bc_fstore_0:
jaroslav@5
   333
                case bc_dstore_0:
jaroslav@5
   334
                    out.append("arg0 = stack.pop();");
jaroslav@5
   335
                    break;
jaroslav@8
   336
                case bc_astore_1:
jaroslav@5
   337
                case bc_istore_1:
jaroslav@5
   338
                case bc_lstore_1:
jaroslav@5
   339
                case bc_fstore_1:
jaroslav@5
   340
                case bc_dstore_1:
jaroslav@5
   341
                    out.append("arg1 = stack.pop();");
jaroslav@5
   342
                    break;
jaroslav@8
   343
                case bc_astore_2:
jaroslav@5
   344
                case bc_istore_2:
jaroslav@5
   345
                case bc_lstore_2:
jaroslav@5
   346
                case bc_fstore_2:
jaroslav@5
   347
                case bc_dstore_2:
jaroslav@5
   348
                    out.append("arg2 = stack.pop();");
jaroslav@5
   349
                    break;
jaroslav@8
   350
                case bc_astore_3:
jaroslav@5
   351
                case bc_istore_3:
jaroslav@5
   352
                case bc_lstore_3:
jaroslav@5
   353
                case bc_fstore_3:
jaroslav@5
   354
                case bc_dstore_3:
jaroslav@5
   355
                    out.append("arg3 = stack.pop();");
jaroslav@5
   356
                    break;
jaroslav@2
   357
                case bc_iadd:
jaroslav@2
   358
                case bc_ladd:
jaroslav@2
   359
                case bc_fadd:
jaroslav@2
   360
                case bc_dadd:
jaroslav@0
   361
                    out.append("stack.push(stack.pop() + stack.pop());");
jaroslav@0
   362
                    break;
jaroslav@2
   363
                case bc_isub:
jaroslav@2
   364
                case bc_lsub:
jaroslav@2
   365
                case bc_fsub:
jaroslav@2
   366
                case bc_dsub:
jaroslav@3
   367
                    out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }");
jaroslav@2
   368
                    break;
jaroslav@2
   369
                case bc_imul:
jaroslav@2
   370
                case bc_lmul:
jaroslav@2
   371
                case bc_fmul:
jaroslav@2
   372
                case bc_dmul:
jaroslav@1
   373
                    out.append("stack.push(stack.pop() * stack.pop());");
jaroslav@1
   374
                    break;
jaroslav@3
   375
                case bc_idiv:
jaroslav@3
   376
                case bc_ldiv:
jaroslav@3
   377
                    out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }");
jaroslav@3
   378
                    break;
jaroslav@3
   379
                case bc_fdiv:
jaroslav@3
   380
                case bc_ddiv:
jaroslav@3
   381
                    out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }");
jaroslav@3
   382
                    break;
jaroslav@7
   383
                case bc_iand:
jaroslav@7
   384
                case bc_land:
jaroslav@7
   385
                    out.append("stack.push(stack.pop() & stack.pop());");
jaroslav@7
   386
                    break;
jaroslav@7
   387
                case bc_ior:
jaroslav@7
   388
                case bc_lor:
jaroslav@7
   389
                    out.append("stack.push(stack.pop() | stack.pop());");
jaroslav@7
   390
                    break;
jaroslav@6
   391
                case bc_ixor:
jaroslav@6
   392
                case bc_lxor:
jaroslav@6
   393
                    out.append("stack.push(stack.pop() ^ stack.pop());");
jaroslav@6
   394
                    break;
jaroslav@93
   395
                case bc_ineg:
jaroslav@93
   396
                case bc_lneg:
jaroslav@93
   397
                case bc_fneg:
jaroslav@93
   398
                case bc_dneg:
jaroslav@93
   399
                    out.append("stack.push(- stack.pop());");
jaroslav@93
   400
                    break;
jaroslav@93
   401
                case bc_ishl:
jaroslav@93
   402
                case bc_lshl:
jaroslav@93
   403
                    out.append("{ var v = stack.pop(); stack.push(stack.pop() << v); }");
jaroslav@93
   404
                    break;
jaroslav@93
   405
                case bc_ishr:
jaroslav@93
   406
                case bc_lshr:
jaroslav@93
   407
                    out.append("{ var v = stack.pop(); stack.push(stack.pop() >> v); }");
jaroslav@93
   408
                    break;
jaroslav@93
   409
                case bc_iushr:
jaroslav@93
   410
                case bc_lushr:
jaroslav@93
   411
                    out.append("{ var v = stack.pop(); stack.push(stack.pop() >>> v); }");
jaroslav@93
   412
                    break;
jaroslav@5
   413
                case bc_iinc: {
jaroslav@5
   414
                    final int varIndx = (byteCodes[++i] + 256) % 256;
jaroslav@104
   415
                    final int incrBy = byteCodes[++i];
jaroslav@5
   416
                    if (incrBy == 1) {
jaroslav@5
   417
                        out.append("arg" + varIndx).append("++;");
jaroslav@5
   418
                    } else {
jaroslav@5
   419
                        out.append("arg" + varIndx).append(" += " + incrBy).append(";");
jaroslav@5
   420
                    }
jaroslav@5
   421
                    break;
jaroslav@5
   422
                }
jaroslav@10
   423
                case bc_return:
jaroslav@10
   424
                    out.append("return;");
jaroslav@10
   425
                    break;
jaroslav@2
   426
                case bc_ireturn:
jaroslav@2
   427
                case bc_lreturn:
jaroslav@2
   428
                case bc_freturn:
jaroslav@2
   429
                case bc_dreturn:
jaroslav@10
   430
                case bc_areturn:
jaroslav@0
   431
                    out.append("return stack.pop();");
jaroslav@1
   432
                    break;
jaroslav@2
   433
                case bc_i2l:
jaroslav@2
   434
                case bc_i2f:
jaroslav@2
   435
                case bc_i2d:
jaroslav@2
   436
                case bc_l2i:
jaroslav@3
   437
                    // max int check?
jaroslav@2
   438
                case bc_l2f:
jaroslav@2
   439
                case bc_l2d:
jaroslav@3
   440
                case bc_f2d:
jaroslav@3
   441
                case bc_d2f:
jaroslav@3
   442
                    out.append("/* number conversion */");
jaroslav@3
   443
                    break;
jaroslav@2
   444
                case bc_f2i:
jaroslav@2
   445
                case bc_f2l:
jaroslav@2
   446
                case bc_d2i:
jaroslav@2
   447
                case bc_d2l:
jaroslav@3
   448
                    out.append("stack.push(Math.floor(stack.pop()));");
jaroslav@3
   449
                    break;
jaroslav@2
   450
                case bc_i2b:
jaroslav@2
   451
                case bc_i2c:
jaroslav@2
   452
                case bc_i2s:
jaroslav@2
   453
                    out.append("/* number conversion */");
jaroslav@2
   454
                    break;
jaroslav@46
   455
                case bc_aconst_null:
jaroslav@46
   456
                    out.append("stack.push(null);");
jaroslav@46
   457
                    break;
jaroslav@48
   458
                case bc_iconst_m1:
jaroslav@48
   459
                    out.append("stack.push(-1);");
jaroslav@48
   460
                    break;
jaroslav@4
   461
                case bc_iconst_0:
jaroslav@4
   462
                case bc_dconst_0:
jaroslav@4
   463
                case bc_lconst_0:
jaroslav@4
   464
                case bc_fconst_0:
jaroslav@4
   465
                    out.append("stack.push(0);");
jaroslav@4
   466
                    break;
jaroslav@4
   467
                case bc_iconst_1:
jaroslav@4
   468
                case bc_lconst_1:
jaroslav@4
   469
                case bc_fconst_1:
jaroslav@4
   470
                case bc_dconst_1:
jaroslav@4
   471
                    out.append("stack.push(1);");
jaroslav@4
   472
                    break;
jaroslav@4
   473
                case bc_iconst_2:
jaroslav@4
   474
                case bc_fconst_2:
jaroslav@4
   475
                    out.append("stack.push(2);");
jaroslav@4
   476
                    break;
jaroslav@4
   477
                case bc_iconst_3:
jaroslav@4
   478
                    out.append("stack.push(3);");
jaroslav@4
   479
                    break;
jaroslav@4
   480
                case bc_iconst_4:
jaroslav@4
   481
                    out.append("stack.push(4);");
jaroslav@4
   482
                    break;
jaroslav@4
   483
                case bc_iconst_5:
jaroslav@4
   484
                    out.append("stack.push(5);");
jaroslav@4
   485
                    break;
jaroslav@20
   486
                case bc_ldc: {
jaroslav@21
   487
                    int indx = byteCodes[++i];
jaroslav@20
   488
                    CPEntry entry = jc.getConstantPool().get(indx);
jaroslav@21
   489
                    String v = encodeConstant(entry);
jaroslav@21
   490
                    out.append("stack.push(").append(v).append(");");
jaroslav@20
   491
                    break;
jaroslav@20
   492
                }
jaroslav@8
   493
                case bc_ldc_w:
jaroslav@8
   494
                case bc_ldc2_w: {
jaroslav@8
   495
                    int indx = readIntArg(byteCodes, i);
jaroslav@8
   496
                    CPEntry entry = jc.getConstantPool().get(indx);
jaroslav@8
   497
                    i += 2;
jaroslav@21
   498
                    String v = encodeConstant(entry);
jaroslav@21
   499
                    out.append("stack.push(").append(v).append(");");
jaroslav@8
   500
                    break;
jaroslav@8
   501
                }
jaroslav@20
   502
                case bc_lcmp:
jaroslav@20
   503
                case bc_fcmpl:
jaroslav@20
   504
                case bc_fcmpg:
jaroslav@20
   505
                case bc_dcmpl:
jaroslav@20
   506
                case bc_dcmpg: {
jaroslav@20
   507
                    out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }");
jaroslav@20
   508
                    break;
jaroslav@20
   509
                }
jaroslav@104
   510
                case bc_if_acmpeq:
jaroslav@104
   511
                    i = generateIf(byteCodes, i, "===");
jaroslav@104
   512
                    break;
jaroslav@104
   513
                case bc_if_acmpne:
jaroslav@104
   514
                    i = generateIf(byteCodes, i, "!=");
jaroslav@104
   515
                    break;
jaroslav@4
   516
                case bc_if_icmpeq: {
jaroslav@4
   517
                    i = generateIf(byteCodes, i, "==");
jaroslav@4
   518
                    break;
jaroslav@4
   519
                }
jaroslav@7
   520
                case bc_ifeq: {
jaroslav@7
   521
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@7
   522
                    out.append("if (stack.pop() == 0) { gt = " + indx);
jaroslav@7
   523
                    out.append("; continue; }");
jaroslav@7
   524
                    i += 2;
jaroslav@7
   525
                    break;
jaroslav@7
   526
                }
jaroslav@20
   527
                case bc_ifne: {
jaroslav@20
   528
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@20
   529
                    out.append("if (stack.pop() != 0) { gt = " + indx);
jaroslav@20
   530
                    out.append("; continue; }");
jaroslav@20
   531
                    i += 2;
jaroslav@20
   532
                    break;
jaroslav@20
   533
                }
jaroslav@20
   534
                case bc_iflt: {
jaroslav@20
   535
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@20
   536
                    out.append("if (stack.pop() < 0) { gt = " + indx);
jaroslav@20
   537
                    out.append("; continue; }");
jaroslav@20
   538
                    i += 2;
jaroslav@20
   539
                    break;
jaroslav@20
   540
                }
jaroslav@20
   541
                case bc_ifle: {
jaroslav@20
   542
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@20
   543
                    out.append("if (stack.pop() <= 0) { gt = " + indx);
jaroslav@20
   544
                    out.append("; continue; }");
jaroslav@20
   545
                    i += 2;
jaroslav@20
   546
                    break;
jaroslav@20
   547
                }
jaroslav@20
   548
                case bc_ifgt: {
jaroslav@20
   549
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@20
   550
                    out.append("if (stack.pop() > 0) { gt = " + indx);
jaroslav@20
   551
                    out.append("; continue; }");
jaroslav@20
   552
                    i += 2;
jaroslav@20
   553
                    break;
jaroslav@20
   554
                }
jaroslav@20
   555
                case bc_ifge: {
jaroslav@20
   556
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@20
   557
                    out.append("if (stack.pop() >= 0) { gt = " + indx);
jaroslav@20
   558
                    out.append("; continue; }");
jaroslav@20
   559
                    i += 2;
jaroslav@20
   560
                    break;
jaroslav@20
   561
                }
jaroslav@16
   562
                case bc_ifnonnull: {
jaroslav@16
   563
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@16
   564
                    out.append("if (stack.pop()) { gt = " + indx);
jaroslav@16
   565
                    out.append("; continue; }");
jaroslav@16
   566
                    i += 2;
jaroslav@16
   567
                    break;
jaroslav@16
   568
                }
jaroslav@16
   569
                case bc_ifnull: {
jaroslav@16
   570
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@16
   571
                    out.append("if (!stack.pop()) { gt = " + indx);
jaroslav@16
   572
                    out.append("; continue; }");
jaroslav@16
   573
                    i += 2;
jaroslav@16
   574
                    break;
jaroslav@16
   575
                }
jaroslav@4
   576
                case bc_if_icmpne:
jaroslav@4
   577
                    i = generateIf(byteCodes, i, "!=");
jaroslav@4
   578
                    break;
jaroslav@4
   579
                case bc_if_icmplt:
jaroslav@4
   580
                    i = generateIf(byteCodes, i, ">");
jaroslav@4
   581
                    break;
jaroslav@4
   582
                case bc_if_icmple:
jaroslav@4
   583
                    i = generateIf(byteCodes, i, ">=");
jaroslav@4
   584
                    break;
jaroslav@4
   585
                case bc_if_icmpgt:
jaroslav@4
   586
                    i = generateIf(byteCodes, i, "<");
jaroslav@4
   587
                    break;
jaroslav@4
   588
                case bc_if_icmpge:
jaroslav@4
   589
                    i = generateIf(byteCodes, i, "<=");
jaroslav@4
   590
                    break;
jaroslav@5
   591
                case bc_goto: {
jaroslav@5
   592
                    int indx = i + readIntArg(byteCodes, i);
jaroslav@5
   593
                    out.append("gt = " + indx).append("; continue;");
jaroslav@5
   594
                    i += 2;
jaroslav@5
   595
                    break;
jaroslav@5
   596
                }
jaroslav@46
   597
                case bc_invokeinterface: {
jaroslav@46
   598
                    i = invokeVirtualMethod(byteCodes, i) + 2;
jaroslav@46
   599
                    break;
jaroslav@46
   600
                }
jaroslav@12
   601
                case bc_invokevirtual:
jaroslav@12
   602
                    i = invokeVirtualMethod(byteCodes, i);
jaroslav@12
   603
                    break;
jaroslav@10
   604
                case bc_invokespecial:
jaroslav@10
   605
                    i = invokeStaticMethod(byteCodes, i, false);
jaroslav@4
   606
                    break;
jaroslav@10
   607
                case bc_invokestatic:
jaroslav@10
   608
                    i = invokeStaticMethod(byteCodes, i, true);
jaroslav@10
   609
                    break;
jaroslav@8
   610
                case bc_new: {
jaroslav@8
   611
                    int indx = readIntArg(byteCodes, i);
jaroslav@8
   612
                    CPClassInfo ci = jc.getConstantPool().getClass(indx);
jaroslav@8
   613
                    out.append("stack.push(");
jaroslav@18
   614
                    out.append("new ").append(ci.getClassName().getInternalName().replace('/','_'));
jaroslav@10
   615
                    out.append(");");
jaroslav@18
   616
                    addReference(ci.getClassName().getInternalName());
jaroslav@8
   617
                    i += 2;
jaroslav@8
   618
                    break;
jaroslav@8
   619
                }
jaroslav@21
   620
                case bc_newarray: {
jaroslav@21
   621
                    int type = byteCodes[i++];
jaroslav@21
   622
                    out.append("stack.push(new Array(stack.pop()));");
jaroslav@21
   623
                    break;
jaroslav@21
   624
                }
jaroslav@21
   625
                case bc_anewarray: {
jaroslav@21
   626
                    i += 2; // skip type of array
jaroslav@21
   627
                    out.append("stack.push(new Array(stack.pop()));");
jaroslav@21
   628
                    break;
jaroslav@21
   629
                }
jaroslav@21
   630
                case bc_arraylength:
jaroslav@21
   631
                    out.append("stack.push(stack.pop().length);");
jaroslav@21
   632
                    break;
jaroslav@21
   633
                case bc_iastore:
jaroslav@21
   634
                case bc_lastore:
jaroslav@21
   635
                case bc_fastore:
jaroslav@21
   636
                case bc_dastore:
jaroslav@21
   637
                case bc_aastore:
jaroslav@21
   638
                case bc_bastore:
jaroslav@21
   639
                case bc_castore:
jaroslav@21
   640
                case bc_sastore: {
jaroslav@21
   641
                    out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }");
jaroslav@21
   642
                    break;
jaroslav@21
   643
                }
jaroslav@21
   644
                case bc_iaload:
jaroslav@21
   645
                case bc_laload:
jaroslav@21
   646
                case bc_faload:
jaroslav@21
   647
                case bc_daload:
jaroslav@21
   648
                case bc_aaload:
jaroslav@21
   649
                case bc_baload:
jaroslav@21
   650
                case bc_caload:
jaroslav@21
   651
                case bc_saload: {
jaroslav@21
   652
                    out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }");
jaroslav@21
   653
                    break;
jaroslav@21
   654
                }
jaroslav@93
   655
                case bc_pop2:
jaroslav@93
   656
                    out.append("stack.pop();");
jaroslav@93
   657
                case bc_pop:
jaroslav@93
   658
                    out.append("stack.pop();");
jaroslav@93
   659
                    break;
jaroslav@8
   660
                case bc_dup:
jaroslav@8
   661
                    out.append("stack.push(stack[stack.length - 1]);");
jaroslav@8
   662
                    break;
jaroslav@8
   663
                case bc_bipush:
jaroslav@8
   664
                    out.append("stack.push(" + byteCodes[++i] + ");");
jaroslav@8
   665
                    break;
jaroslav@31
   666
                case bc_sipush:
jaroslav@31
   667
                    out.append("stack.push(" + readIntArg(byteCodes, i) + ");");
jaroslav@31
   668
                    i += 2;
jaroslav@31
   669
                    break;
jaroslav@8
   670
                case bc_getfield: {
jaroslav@8
   671
                    int indx = readIntArg(byteCodes, i);
jaroslav@8
   672
                    CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
jaroslav@21
   673
                    out.append("stack.push(stack.pop().").append(fi.getFieldName()).append(");");
jaroslav@8
   674
                    i += 2;
jaroslav@8
   675
                    break;
jaroslav@8
   676
                }
jaroslav@9
   677
                case bc_getstatic: {
jaroslav@9
   678
                    int indx = readIntArg(byteCodes, i);
jaroslav@9
   679
                    CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
jaroslav@18
   680
                    final String in = fi.getClassName().getInternalName();
jaroslav@18
   681
                    out.append("stack.push(").append(in.replace('/', '_'));
jaroslav@9
   682
                    out.append('_').append(fi.getFieldName()).append(");");
jaroslav@9
   683
                    i += 2;
jaroslav@18
   684
                    addReference(in);
jaroslav@9
   685
                    break;
jaroslav@9
   686
                }
jaroslav@9
   687
                case bc_putstatic: {
jaroslav@9
   688
                    int indx = readIntArg(byteCodes, i);
jaroslav@9
   689
                    CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
jaroslav@18
   690
                    final String in = fi.getClassName().getInternalName();
jaroslav@18
   691
                    out.append(in.replace('/', '_'));
jaroslav@9
   692
                    out.append('_').append(fi.getFieldName()).append(" = stack.pop();");
jaroslav@9
   693
                    i += 2;
jaroslav@18
   694
                    addReference(in);
jaroslav@9
   695
                    break;
jaroslav@9
   696
                }
jaroslav@10
   697
                case bc_putfield: {
jaroslav@10
   698
                    int indx = readIntArg(byteCodes, i);
jaroslav@10
   699
                    CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx);
jaroslav@10
   700
                    out.append("{ var v = stack.pop(); stack.pop().")
jaroslav@10
   701
                       .append(fi.getFieldName()).append(" = v; }");
jaroslav@10
   702
                    i += 2;
jaroslav@10
   703
                    break;
jaroslav@10
   704
                }
jaroslav@30
   705
                case bc_checkcast: {
jaroslav@30
   706
                    int indx = readIntArg(byteCodes, i);
jaroslav@30
   707
                    CPClassInfo ci = jc.getConstantPool().getClass(indx);
jaroslav@42
   708
                    final String type = ci.getClassName().getType();
jaroslav@42
   709
                    if (!type.startsWith("[")) {
jaroslav@42
   710
                        // no way to check arrays right now
jaroslav@42
   711
                        out.append("if(stack[stack.length - 1].$instOf_")
jaroslav@42
   712
                           .append(type.replace('/', '_'))
jaroslav@42
   713
                           .append(" != 1) throw {};"); // XXX proper exception
jaroslav@42
   714
                    }
jaroslav@30
   715
                    i += 2;
jaroslav@30
   716
                    break;
jaroslav@30
   717
                }
jaroslav@17
   718
                case bc_instanceof: {
jaroslav@17
   719
                    int indx = readIntArg(byteCodes, i);
jaroslav@17
   720
                    CPClassInfo ci = jc.getConstantPool().getClass(indx);
jaroslav@17
   721
                    out.append("stack.push(stack.pop().$instOf_")
jaroslav@18
   722
                       .append(ci.getClassName().getInternalName().replace('/', '_'))
jaroslav@17
   723
                       .append(" ? 1 : 0);");
jaroslav@17
   724
                    i += 2;
jaroslav@30
   725
                    break;
jaroslav@17
   726
                }
jaroslav@104
   727
                case bc_athrow: {
jaroslav@104
   728
                    out.append("{ var t = stack.pop(); stack = new Array(1); stack[0] = t; throw t; }");
jaroslav@104
   729
                    break;
jaroslav@104
   730
                }
jaroslav@104
   731
                default: {
jaroslav@104
   732
                    out.append("throw 'unknown bytecode " + c + "';");
jaroslav@104
   733
                }
jaroslav@8
   734
                    
jaroslav@0
   735
            }
tzezula@285
   736
            if (!current.isEmpty()) {
tzezula@285
   737
                out.append("} catch (e) {");
tzezula@285
   738
                for (ExceptionTableEntry e : current) {
tzezula@285
   739
                    if (e.getCatchType() != null) {
tzezula@285
   740
                        final String classInternalName = e.getCatchType().getClassName().getInternalName();
tzezula@285
   741
                        addReference(classInternalName);
tzezula@285
   742
                        out.append("if (e.$instOf_"+classInternalName.replace('/', '_')+") {");
tzezula@285
   743
                        out.append("gt="+e.getHandlerPC()+"; continue;");
tzezula@285
   744
                        out.append("} ");
tzezula@285
   745
                    } else {
tzezula@285
   746
                        //finally - todo
tzezula@285
   747
                    }
tzezula@285
   748
                }
tzezula@285
   749
                out.append("throw e;");
tzezula@285
   750
                out.append("}");
tzezula@285
   751
            }
jaroslav@39
   752
            out.append(" //");
jaroslav@0
   753
            for (int j = prev; j <= i; j++) {
jaroslav@0
   754
                out.append(" ");
jaroslav@0
   755
                final int cc = (byteCodes[j] + 256) % 256;
jaroslav@0
   756
                out.append(Integer.toString(cc));
jaroslav@0
   757
            }
tzezula@285
   758
            out.append("\n");            
jaroslav@0
   759
        }
jaroslav@10
   760
        out.append("  }\n");
jaroslav@4
   761
    }
jaroslav@4
   762
jaroslav@4
   763
    private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
jaroslav@4
   764
        int indx = i + readIntArg(byteCodes, i);
jaroslav@4
   765
        out.append("if (stack.pop() ").append(test).append(" stack.pop()) { gt = " + indx);
jaroslav@4
   766
        out.append("; continue; }");
jaroslav@4
   767
        return i + 2;
jaroslav@4
   768
    }
jaroslav@4
   769
jaroslav@4
   770
    private int readIntArg(byte[] byteCodes, int offsetInstruction) {
jaroslav@5
   771
        final int indxHi = byteCodes[offsetInstruction + 1] << 8;
jaroslav@5
   772
        final int indxLo = byteCodes[offsetInstruction + 2];
jaroslav@5
   773
        return (indxHi & 0xffffff00) | (indxLo & 0xff);
jaroslav@4
   774
    }
jaroslav@4
   775
    
jaroslav@4
   776
    private static int countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig) {
jaroslav@4
   777
        int cnt = 0;
jaroslav@4
   778
        int i = 0;
jaroslav@4
   779
        Boolean count = null;
jaroslav@32
   780
        boolean array = false;
jaroslav@10
   781
        int firstPos = sig.length();
jaroslav@4
   782
        while (i < descriptor.length()) {
jaroslav@4
   783
            char ch = descriptor.charAt(i++);
jaroslav@4
   784
            switch (ch) {
jaroslav@4
   785
                case '(':
jaroslav@4
   786
                    count = true;
jaroslav@4
   787
                    continue;
jaroslav@4
   788
                case ')':
jaroslav@4
   789
                    count = false;
jaroslav@4
   790
                    continue;
jaroslav@32
   791
                case 'A':
jaroslav@32
   792
                    array = true;
jaroslav@32
   793
                    break;
jaroslav@4
   794
                case 'B': 
jaroslav@4
   795
                case 'C': 
jaroslav@4
   796
                case 'D': 
jaroslav@4
   797
                case 'F': 
jaroslav@4
   798
                case 'I': 
jaroslav@4
   799
                case 'J': 
jaroslav@4
   800
                case 'S': 
jaroslav@4
   801
                case 'Z': 
jaroslav@4
   802
                    if (count) {
jaroslav@4
   803
                        cnt++;
jaroslav@32
   804
                        if (array) {
jaroslav@32
   805
                            sig.append('A');
jaroslav@32
   806
                        }
jaroslav@4
   807
                        sig.append(ch);
jaroslav@4
   808
                    } else {
jaroslav@4
   809
                        hasReturnType[0] = true;
jaroslav@10
   810
                        sig.insert(firstPos, ch);
jaroslav@32
   811
                        if (array) {
jaroslav@32
   812
                            sig.insert(firstPos, 'A');
jaroslav@32
   813
                        }
jaroslav@4
   814
                    }
jaroslav@93
   815
                    array = false;
jaroslav@4
   816
                    continue;
jaroslav@4
   817
                case 'V': 
jaroslav@4
   818
                    assert !count;
jaroslav@4
   819
                    hasReturnType[0] = false;
jaroslav@10
   820
                    sig.insert(firstPos, 'V');
jaroslav@4
   821
                    continue;
jaroslav@4
   822
                case 'L':
jaroslav@16
   823
                    int next = descriptor.indexOf(';', i);
jaroslav@4
   824
                    if (count) {
jaroslav@4
   825
                        cnt++;
jaroslav@32
   826
                        if (array) {
jaroslav@32
   827
                            sig.append('A');
jaroslav@32
   828
                        }
jaroslav@16
   829
                        sig.append(ch);
jaroslav@16
   830
                        sig.append(descriptor.substring(i, next).replace('/', '_'));
jaroslav@4
   831
                    } else {
jaroslav@16
   832
                        sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_'));
jaroslav@16
   833
                        sig.insert(firstPos, ch);
jaroslav@32
   834
                        if (array) {
jaroslav@33
   835
                            sig.insert(firstPos, 'A');
jaroslav@32
   836
                        }
jaroslav@4
   837
                        hasReturnType[0] = true;
jaroslav@4
   838
                    }
jaroslav@16
   839
                    i = next + 1;
jaroslav@4
   840
                    continue;
jaroslav@4
   841
                case '[':
jaroslav@4
   842
                    //arrays++;
jaroslav@4
   843
                    continue;
jaroslav@4
   844
                default:
jaroslav@4
   845
                    break; // invalid character
jaroslav@4
   846
            }
jaroslav@4
   847
        }
jaroslav@4
   848
        return cnt;
jaroslav@0
   849
    }
jaroslav@9
   850
jaroslav@9
   851
    private void generateStaticField(Variable v) throws IOException {
jaroslav@9
   852
        out.append("\nvar ")
jaroslav@18
   853
           .append(jc.getName().getInternalName().replace('/', '_'))
jaroslav@9
   854
           .append('_').append(v.getName()).append(" = 0;");
jaroslav@9
   855
    }
jaroslav@10
   856
jaroslav@10
   857
    private String findMethodName(Method m) {
jaroslav@42
   858
        StringBuilder name = new StringBuilder();
jaroslav@42
   859
        String descr = m.getDescriptor();
jaroslav@10
   860
        if ("<init>".equals(m.getName())) { // NOI18N
jaroslav@42
   861
            name.append("cons"); // NOI18N
jaroslav@19
   862
        } else if ("<clinit>".equals(m.getName())) { // NOI18N
jaroslav@42
   863
            name.append("class"); // NOI18N
jaroslav@10
   864
        } else {
jaroslav@42
   865
            name.append(m.getName());
jaroslav@10
   866
        } 
jaroslav@42
   867
        
jaroslav@42
   868
        boolean hasReturn[] = { false };
jaroslav@42
   869
        countArgs(findDescriptor(m.getDescriptor()), hasReturn, name);
jaroslav@42
   870
        return name.toString();
jaroslav@10
   871
    }
jaroslav@10
   872
jaroslav@10
   873
    private String findMethodName(CPMethodInfo mi, int[] cnt, boolean[] hasReturn) {
jaroslav@10
   874
        StringBuilder name = new StringBuilder();
jaroslav@42
   875
        String descr = mi.getDescriptor();
jaroslav@10
   876
        if ("<init>".equals(mi.getName())) { // NOI18N
jaroslav@10
   877
            name.append("cons"); // NOI18N
jaroslav@10
   878
        } else {
jaroslav@10
   879
            name.append(mi.getName());
jaroslav@10
   880
        }
jaroslav@32
   881
        cnt[0] = countArgs(findDescriptor(mi.getDescriptor()), hasReturn, name);
jaroslav@10
   882
        return name.toString();
jaroslav@10
   883
    }
jaroslav@10
   884
jaroslav@10
   885
    private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
jaroslav@10
   886
    throws IOException {
jaroslav@10
   887
        int methodIndex = readIntArg(byteCodes, i);
jaroslav@10
   888
        CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex);
jaroslav@10
   889
        boolean[] hasReturn = { false };
jaroslav@10
   890
        int[] cnt = { 0 };
jaroslav@10
   891
        String mn = findMethodName(mi, cnt, hasReturn);
jaroslav@11
   892
        out.append("{ ");
jaroslav@11
   893
        for (int j = cnt[0] - 1; j >= 0; j--) {
jaroslav@11
   894
            out.append("var v" + j).append(" = stack.pop(); ");
jaroslav@11
   895
        }
jaroslav@11
   896
        
jaroslav@10
   897
        if (hasReturn[0]) {
jaroslav@10
   898
            out.append("stack.push(");
jaroslav@10
   899
        }
jaroslav@18
   900
        final String in = mi.getClassName().getInternalName();
jaroslav@18
   901
        out.append(in.replace('/', '_'));
jaroslav@102
   902
        if (isStatic) {
jaroslav@102
   903
            out.append(".prototype.");
jaroslav@102
   904
        } else {
jaroslav@102
   905
            out.append('_');
jaroslav@102
   906
        }
jaroslav@10
   907
        out.append(mn);
jaroslav@10
   908
        out.append('(');
jaroslav@10
   909
        String sep = "";
jaroslav@10
   910
        if (!isStatic) {
jaroslav@10
   911
            out.append("stack.pop()");
jaroslav@10
   912
            sep = ", ";
jaroslav@10
   913
        }
jaroslav@10
   914
        for (int j = 0; j < cnt[0]; j++) {
jaroslav@10
   915
            out.append(sep);
jaroslav@11
   916
            out.append("v" + j);
jaroslav@10
   917
            sep = ", ";
jaroslav@10
   918
        }
jaroslav@10
   919
        out.append(")");
jaroslav@10
   920
        if (hasReturn[0]) {
jaroslav@10
   921
            out.append(")");
jaroslav@10
   922
        }
jaroslav@11
   923
        out.append("; }");
jaroslav@10
   924
        i += 2;
jaroslav@18
   925
        addReference(in);
jaroslav@10
   926
        return i;
jaroslav@10
   927
    }
jaroslav@12
   928
    private int invokeVirtualMethod(byte[] byteCodes, int i)
jaroslav@12
   929
    throws IOException {
jaroslav@12
   930
        int methodIndex = readIntArg(byteCodes, i);
jaroslav@12
   931
        CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex);
jaroslav@12
   932
        boolean[] hasReturn = { false };
jaroslav@12
   933
        int[] cnt = { 0 };
jaroslav@12
   934
        String mn = findMethodName(mi, cnt, hasReturn);
jaroslav@12
   935
        out.append("{ ");
jaroslav@12
   936
        for (int j = cnt[0] - 1; j >= 0; j--) {
jaroslav@12
   937
            out.append("var v" + j).append(" = stack.pop(); ");
jaroslav@12
   938
        }
jaroslav@12
   939
        out.append("var self = stack.pop(); ");
jaroslav@12
   940
        if (hasReturn[0]) {
jaroslav@12
   941
            out.append("stack.push(");
jaroslav@12
   942
        }
jaroslav@12
   943
        out.append("self.");
jaroslav@12
   944
        out.append(mn);
jaroslav@12
   945
        out.append('(');
jaroslav@12
   946
        out.append("self");
jaroslav@12
   947
        for (int j = 0; j < cnt[0]; j++) {
jaroslav@12
   948
            out.append(", ");
jaroslav@12
   949
            out.append("v" + j);
jaroslav@12
   950
        }
jaroslav@12
   951
        out.append(")");
jaroslav@12
   952
        if (hasReturn[0]) {
jaroslav@12
   953
            out.append(")");
jaroslav@12
   954
        }
jaroslav@12
   955
        out.append("; }");
jaroslav@12
   956
        i += 2;
jaroslav@12
   957
        return i;
jaroslav@12
   958
    }
jaroslav@18
   959
    
jaroslav@103
   960
    private void addReference(String cn) throws IOException {
jaroslav@103
   961
        out.append(" /* needs ").append(cn).append(" */");
jaroslav@18
   962
        if (references != null) {
jaroslav@18
   963
            references.add(cn);
jaroslav@18
   964
        }
jaroslav@18
   965
    }
jaroslav@16
   966
jaroslav@33
   967
    private void outType(String d, StringBuilder out) {
jaroslav@33
   968
        int arr = 0;
jaroslav@33
   969
        while (d.charAt(0) == '[') {
jaroslav@33
   970
            out.append('A');
jaroslav@33
   971
            d = d.substring(1);
jaroslav@33
   972
        }
jaroslav@16
   973
        if (d.charAt(0) == 'L') {
jaroslav@16
   974
            assert d.charAt(d.length() - 1) == ';';
jaroslav@16
   975
            out.append(d.replace('/', '_').substring(0, d.length() - 1));
jaroslav@16
   976
        } else {
jaroslav@16
   977
            out.append(d);
jaroslav@16
   978
        }
jaroslav@16
   979
    }
jaroslav@21
   980
jaroslav@21
   981
    private String encodeConstant(CPEntry entry) {
jaroslav@21
   982
        final String v;
jaroslav@93
   983
        if (entry instanceof CPClassInfo) {
jaroslav@93
   984
            v = "new java_lang_Class";
jaroslav@93
   985
        } else if (entry instanceof CPStringInfo) {
jaroslav@21
   986
            v = "\"" + entry.getValue().toString().replace("\"", "\\\"") + "\"";
jaroslav@21
   987
        } else {
jaroslav@21
   988
            v = entry.getValue().toString();
jaroslav@21
   989
        }
jaroslav@21
   990
        return v;
jaroslav@21
   991
    }
jaroslav@32
   992
jaroslav@32
   993
    private String findDescriptor(String d) {
jaroslav@32
   994
        return d.replace('[', 'A');
jaroslav@32
   995
    }
jaroslav@94
   996
jaroslav@94
   997
    private boolean javaScriptBody(Method m, boolean isStatic) throws IOException {
jaroslav@94
   998
        final ClassName extraAnn = ClassName.getClassName(JavaScriptBody.class.getName().replace('.', '/'));
jaroslav@94
   999
        Annotation a = m.getAnnotation(extraAnn);
jaroslav@94
  1000
        if (a != null) {
jaroslav@94
  1001
            final ElementValue annVal = a.getComponent("body").getValue();
jaroslav@94
  1002
            String body = ((PrimitiveElementValue) annVal).getValue().getValue().toString();
jaroslav@94
  1003
            
jaroslav@94
  1004
            final ArrayElementValue arrVal = (ArrayElementValue) a.getComponent("args").getValue();
jaroslav@94
  1005
            final int len = arrVal.getValues().length;
jaroslav@94
  1006
            String[] names = new String[len];
jaroslav@94
  1007
            for (int i = 0; i < len; i++) {
jaroslav@94
  1008
                names[i] = ((PrimitiveElementValue) arrVal.getValues()[i]).getValue().getValue().toString();
jaroslav@94
  1009
            }
jaroslav@94
  1010
            out.append("\nfunction ").append(
jaroslav@94
  1011
                jc.getName().getInternalName().replace('/', '_')).append('_').append(findMethodName(m));
jaroslav@94
  1012
            out.append("(");
jaroslav@94
  1013
            String space;
jaroslav@94
  1014
            int index;
jaroslav@94
  1015
            if (!isStatic) {                
jaroslav@94
  1016
                out.append(names[0]);
jaroslav@94
  1017
                space = ",";
jaroslav@94
  1018
                index = 1;
jaroslav@94
  1019
            } else {
jaroslav@94
  1020
                space = "";
jaroslav@94
  1021
                index = 0;
jaroslav@94
  1022
            }
jaroslav@94
  1023
            List<Parameter> args = m.getParameters();
jaroslav@94
  1024
            for (int i = 0; i < args.size(); i++) {
jaroslav@94
  1025
                out.append(space);
jaroslav@94
  1026
                out.append(names[index]);
jaroslav@94
  1027
                final String desc = findDescriptor(args.get(i).getDescriptor());
jaroslav@94
  1028
                index++;
jaroslav@99
  1029
                space = ",";
jaroslav@94
  1030
            }
jaroslav@94
  1031
            out.append(") {").append("\n");
jaroslav@94
  1032
            out.append(body);
jaroslav@94
  1033
            out.append("\n}\n");
jaroslav@94
  1034
            return true;
jaroslav@94
  1035
        }
jaroslav@94
  1036
        return false;
jaroslav@94
  1037
    }
jaroslav@0
  1038
}