/* jadecode.c:  Copyright (C) Codemist Ltd., 1996.                      */

#include <stdio.h>
#include <string.h>
#include "machine.h"
#include "tags.h"
#include "cslerror.h"
#include "externs.h"
#include "read.h"
#include "stream.h"
#include "arith.h"
#include "entries.h"
#include "javahost.h"
#include "javaglb.h"

static struct { char *opname; } optable[211] = {
  "\x00""nop",			/* 0 */
  "\x00""aconst_null",		/* 1 */
  "\x00""iconst_m1",		/* 2 */
  "\x00""iconst_0",		/* 3 */
  "\x00""iconst_1",		/* 4 */
  "\x00""iconst_2",		/* 5 */
  "\x00""iconst_3",		/* 6 */
  "\x00""iconst_4",		/* 7 */
  "\x00""iconst_5",		/* 8 */
  "\x00""lconst_0",		/* 9 */
  "\x00""lconst_1",		/* 10 */
  "\x00""fconst_0",		/* 11 */
  "\x00""fconst_1",		/* 12 */
  "\x00""fconst_2",		/* 13 */
  "\x00""dconst_0",		/* 14 */
  "\x00""dconst_1",		/* 15 */
  "\x01""bipush",		/* 16 */
  "\x02""sipush",		/* 17 */
  "\x11""ldc1",			/* 18 */
  "\x12""ldc2",			/* 19 */
  "\x12""ldc2w",		/* 20 */
  "\x01""iload",		/* 21 */
  "\x01""lload",		/* 22 */
  "\x01""fload",		/* 23 */
  "\x01""dload",		/* 24 */
  "\x01""aload",		/* 25 */
  "\x00""iload_0",		/* 26 */
  "\x00""iload_1",		/* 27 */
  "\x00""iload_2",		/* 28 */
  "\x00""iload_3",		/* 29 */
  "\x00""lload_0",		/* 30 */
  "\x00""lload_1",		/* 31 */
  "\x00""lload_2",		/* 32 */
  "\x00""lload_3",		/* 33 */
  "\x00""fload_0",		/* 34 */
  "\x00""fload_1",		/* 35 */
  "\x00""fload_2",		/* 36 */
  "\x00""fload_3",		/* 37 */
  "\x00""dload_0",		/* 38 */
  "\x00""dload_1",		/* 39 */
  "\x00""dload_2",		/* 40 */
  "\x00""dload_3",		/* 41 */
  "\x00""aload_0",		/* 42 */
  "\x00""aload_1",		/* 43 */
  "\x00""aload_2",		/* 44 */
  "\x00""aload_3",		/* 45 */
  "\x00""iaload",		/* 46 */
  "\x00""laload",		/* 47 */
  "\x00""faload",		/* 48 */
  "\x00""daload",		/* 49 */
  "\x00""aaload",		/* 50 */
  "\x00""baload",		/* 51 */
  "\x00""caload",		/* 52 */
  "\x00""saload",		/* 53 */
  "\x01""istore",		/* 54 */
  "\x01""lstore",		/* 55 */
  "\x01""fstore",		/* 56 */
  "\x01""dstore",		/* 57 */
  "\x01""astore",		/* 58 */
  "\x00""istore_0",		/* 59 */
  "\x00""istore_1",		/* 60 */
  "\x00""istore_2",		/* 61 */
  "\x00""istore_3",		/* 62 */
  "\x00""lstore_0",		/* 63 */
  "\x00""lstore_1",		/* 64 */
  "\x00""lstore_2",		/* 65 */
  "\x00""lstore_3",		/* 66 */
  "\x00""fstore_0",		/* 67 */
  "\x00""fstore_1",		/* 68 */
  "\x00""fstore_2",		/* 69 */
  "\x00""fstore_3",		/* 70 */
  "\x00""dstore_0",		/* 71 */
  "\x00""dstore_1",		/* 72 */
  "\x00""dstore_2",		/* 73 */
  "\x00""dstore_3",		/* 74 */
  "\x00""astore_0",		/* 75 */
  "\x00""astore_1",		/* 76 */
  "\x00""astore_2",		/* 77 */
  "\x00""astore_3",		/* 78 */
  "\x00""iastore",		/* 79 */
  "\x00""lastore",		/* 80 */
  "\x00""fastore",		/* 81 */
  "\x00""dastore",		/* 82 */
  "\x00""aastore",		/* 83 */
  "\x00""bastore",		/* 84 */
  "\x00""castore",		/* 85 */
  "\x00""sastore",		/* 86 */
  "\x00""pop",			/* 87 */
  "\x00""pop2",			/* 88 */
  "\x00""dup",			/* 89 */
  "\x00""dup_x1",		/* 90 */
  "\x00""dup_x2",		/* 91 */
  "\x00""dup2",			/* 92 */
  "\x00""dup2_x1",		/* 93 */
  "\x00""dup2_x2",		/* 94 */
  "\x00""swap",			/* 95 */
  "\x00""iadd",			/* 96 */
  "\x00""ladd",			/* 97 */
  "\x00""fadd",			/* 98 */
  "\x00""dadd",			/* 99 */
  "\x00""isub",			/* 100 */
  "\x00""lsub",			/* 101 */
  "\x00""fsub",			/* 102 */
  "\x00""dsub",			/* 103 */
  "\x00""imul",			/* 104 */
  "\x00""lmul",			/* 105 */
  "\x00""fmul",			/* 106 */
  "\x00""dmul",			/* 107 */
  "\x00""idiv",			/* 108 */
  "\x00""ldiv",			/* 109 */
  "\x00""fdiv",			/* 110 */
  "\x00""ddiv",			/* 111 */
  "\x00""irem",			/* 112 */
  "\x00""lrem",			/* 113 */
  "\x00""frem",			/* 114 */
  "\x00""drem",			/* 115 */
  "\x00""ineg",			/* 116 */
  "\x00""lneg",			/* 117 */
  "\x00""fneg",			/* 118 */
  "\x00""dneg",			/* 119 */
  "\x00""ishl",			/* 120 */
  "\x00""ishr",			/* 121 */
  "\x00""iushr",		/* 122 */
  "\x00""lshl",			/* 123 */
  "\x00""lshr",			/* 124 */
  "\x00""lushr",		/* 125 */
  "\x00""iand",			/* 126 */
  "\x00""land",			/* 127 */
  "\x00""ior",			/* 128 */
  "\x00""lor",			/* 129 */
  "\x00""ixor",			/* 130 */
  "\x00""lxor",			/* 131 */
  "\x03""iinc",			/* 132 */
  "\x00""i2l",			/* 133 */
  "\x00""i2f",			/* 134 */
  "\x00""i2d",			/* 135 */
  "\x00""l2i",			/* 136 */
  "\x00""l2f",			/* 137 */
  "\x00""l2d",			/* 138 */
  "\x00""f2i",			/* 139 */
  "\x00""f2l",			/* 140 */
  "\x00""f2d",			/* 141 */
  "\x00""d2i",			/* 142 */
  "\x00""d2l",			/* 143 */
  "\x00""d2f",			/* 144 */
  "\x00""int2byte",		/* 145 */
  "\x00""int2char",		/* 146 */
  "\x00""int2short",		/* 147 */
  "\x00""lcmp",			/* 148 */
  "\x00""fcmpl",		/* 149 */
  "\x00""fcmpg",		/* 150 */
  "\x00""dcmpl",		/* 151 */
  "\x00""dcmpg",		/* 152 */
  "\x08""ifeq",			/* 153 */
  "\x08""ifne",			/* 154 */
  "\x08""iflt",			/* 155 */
  "\x08""ifge",			/* 156 */
  "\x08""ifgt",			/* 157 */
  "\x08""ifle",			/* 158 */
  "\x08""if_icmpeq",		/* 159 */
  "\x08""if_icmpne",		/* 160 */
  "\x08""if_icmplt",		/* 161 */
  "\x08""if_icmpge",		/* 162 */
  "\x08""if_icmpgt",		/* 163 */
  "\x08""if_icmple",		/* 164 */
  "\x08""if_acmpeq",		/* 165 */
  "\x08""if_acmpne",		/* 166 */
  "\x08""goto",			/* 167 */
  "\x08""jsr",			/* 168 */
  "\x01""ret",			/* 169 */
  "\x06""tableswitch",		/* 170 */
  "\x07""lookupswitch",		/* 171 */
  "\x00""ireturn",		/* 172 */
  "\x00""lreturn",		/* 173 */
  "\x00""freturn",		/* 174 */
  "\x00""dreturn",		/* 175 */
  "\x00""areturn",		/* 176 */
  "\x00""return",		/* 177 */
  "\x12""getstatic",		/* 178 */
  "\x12""putstatic",		/* 179 */
  "\x12""getfield",		/* 180 */
  "\x12""putfield",		/* 181 */
  "\x12""invokevirtual",	/* 182 */
  "\x12""invokenonvirtual",	/* 183 */
  "\x12""invokestatic",		/* 184 */
  "\x14""invokeinterface",	/* 185 */
  "\x00""<missing186>",             /* 186 */
  "\x12""new",			/* 187 */
  "\x01""newarray",		/* 188 */
  "\x12""anewarray",		/* 189 */
  "\x00""arraylength",		/* 190 */
  "\x00""athrow",		/* 191 */
  "\x12""checkcast",		/* 192 */
  "\x12""instanceof",		/* 193 */
  "\x00""monitorenter",		/* 194 */
  "\x00""monitorexit",		/* 195 */
  "\x01""wide",			/* 196 */
  "\x13""multinewarray",	/* 197 */
  "\x08""ifnull",		/* 198 */
  "\x08""ifnonnull",		/* 199 */
  "\x09""goto_w",		/* 200 */
  "\x09""jsr_w",		/* 201 */
  "\x00""breakpoint",		/* 202 */
  "\x00""<missing203>",             /* 203 */
  "\x00""<missing204>",             /* 204 */
  "\x00""<missing205>",             /* 205 */
  "\x00""<missing206>",             /* 206 */
  "\x00""<missing207>",             /* 207 */
  "\x00""<missing208>",             /* 208 */
  "\x02""ret_w",		/* 209 */
  "\x00""<missing >= 210>" };

static unsigned char *labtab;

static void notelab(unsigned32 l)
{   if (l < 0x10000) labtab[l/8] |= 1 << (l%8);
    /* err_printf("notelab %d\n", l); */
}

static int islab(unsigned32 l)
{   int b = 1 << l%8;
    /* err_printf("islab %d\n", l); */
    if (l < 0x10000 && labtab[l/8] & b)
    {   /* labtab[l/8] ^= b; */
        return 1;
    }
    return 0;
}

static int reflab(unsigned32 l)
{   int b = 1 << l%8;
    if (l < 0x10000 && labtab[l/8] & b)
    {   err_printf("L%.4x", l);
        return 1;
    }
    return 0;
}

#define ztos16(w) (((unsigned32)(w) ^ 0x8000) - 0x8000)

static void decode_lit(unsigned32 n, Cp_Info *cp, unsigned32 cplen)
{   for (;;)
    {   if (n == 0 || n >= cplen)
        {   err_printf("<bad literal 0x%x>", n);
            return;
        }
        else switch (cp[n].tag)
        {
case CONSTANT_Class:            err_printf("Class"); goto redo;
case CONSTANT_FieldRef:         err_printf("FieldRef"); goto redo2;
case CONSTANT_MethodRef:        err_printf("MethodRef"); goto redo2;
case CONSTANT_InterfaceMethodRef: err_printf("InterfaceMethodRef"); goto redo2;
case CONSTANT_String:           err_printf("String"); goto redo;
case CONSTANT_Integer:          err_printf("Integer:%d",n); return;
case CONSTANT_Float:            err_printf("Float:%d",n); return;
case CONSTANT_Long:             err_printf("Long:%d",n); return;
case CONSTANT_Double:           err_printf("Double:%d",n); return;
case CONSTANT_Utf8:             err_printf("Utf8[%d'%*s']", n,
                                       cp[n].len, cp[n].u.utf8); return;
case CONSTANT_Unicode:          err_printf("Unicode:%d",n); return;
case CONSTANT_NameAndType:      err_printf("NameAndType"); goto redo2;
default:    err_printf("<unknown literal[%.4x] %d>", n, cp[n].tag); return;
        }
redo:   err_printf("[%d]:", n); n = cp[n].u.val; continue;
redo2:  err_printf("[%d]:<", n);
        decode_lit(cp[n].u.val, cp, cplen);
        err_printf(",");
        decode_lit(cp[n].len, cp, cplen);
        err_printf(">"); return;
    }
}

char *jdecodeopname(unsigned32 op)
{
    if (op >= 210) op = 210;
    return optable[op].opname+1;
}

void javadecode(unsigned8 *code, unsigned32 len, Cp_Info *cp, unsigned32 cplen)
{   unsigned8 *p;
    if (labtab == 0) labtab = (unsigned char *)jmalloc(0x10000/8);
    memset(labtab, 0, 0x10000/8);
    for (p = code; p < code+len;)
    {   unsigned32 op = *p++;
        if (op >= 210) op = 210;
        switch (optable[op].opname[0])
        {
default:    break;
case 0x11:
case 0x01:  p++; break;
case 0x12:
case 0x02:  p += 2; break;
case 0x08:  notelab(p-1-code + ztos16(p[0]<<8 | p[1])); p += 2; break;
case 0x03:  p += 2; break;
case 0x13:  p += 3; break;
case 0x14:
case 0x04:  p += 4; break;
case 0x09:  notelab(p-1-code + (p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3])); p += 4;
            break;
case 0x06:  ("\ttableswitch!"); break;
case 0x07:  ("\tlookupswitch!"); break;
        }
    }
    for (p = code; p < code+len;)
    {   unsigned32 op = *p++;
        unsigned32 off;
        if (op >= 210) op = 210;
        if (islab(p-1 - code)) err_printf("L%.4x:", p-1 - code);
        err_printf("\t%s", optable[op].opname+1);
        if (optable[op].opname[0] != 0x00 && strlen(optable[op].opname+1) < 8)
            err_printf("\t");
        switch (optable[op].opname[0])
        {
default:    break;
case 0x01:  err_printf("\t%d", *p++); break;
case 0x11:  err_printf("\t"); decode_lit(*p++, cp, cplen); break;
case 0x02:  err_printf("\t0x%.4x", p[0]<<8 | p[1]); p += 2; break;
case 0x12:  err_printf("\t"); decode_lit(p[0]<<8 | p[1], cp, cplen); p += 2; break;
case 0x08:  off = ztos16(p[0]<<8 | p[1]);
            err_printf("\t");
            if (!reflab(p-1-code+off)) err_printf("$+0x%.4x", off);
            p += 2; break;
case 0x03:  err_printf("\t%d,%d", p[0], p[1]); p += 2; break;
case 0x13:  err_printf("\t"); decode_lit(p[0]<<8 | p[1], cp, cplen);
            err_printf(",%d", p[2]); p += 3; break;
case 0x14:  err_printf("\t"); decode_lit(p[0]<<8 | p[1], cp, cplen);
            err_printf(",%d,%d", p[2], p[3]); p += 4; break;
case 0x04:  err_printf("\t0x%.8x", p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3]); p += 4;
            break;
case 0x09:  off = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
            err_printf("\t(big)");
            if (!reflab(p-1-code+off)) err_printf("\t$+0x%.8x", off);
            p += 4; break;
case 0x06:  err_printf("\tswitch!");
            break;
case 0x07:  err_printf("\tswitch!");
            break;
        }
        err_printf("\n");
    }
}

/* end of jadecode.c */
