home *** CD-ROM | disk | FTP | other *** search
- /*
- * translator.c
- * Bytecode translator.
- *
- * Copyright (c) 1996 Systems Architecture Research Centre,
- * City University, London, UK.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * Written by Tim Wilkinson <tim@sarc.city.ac.uk>, February 1996.
- */
-
- #include <stdio.h>
- #include <assert.h>
- #include "errors.h"
- #include "file.h"
- #include "bytecode.h"
- #include "instruction.h"
- #include "code.h"
- #include "classMethod.h"
- #include "constants.h"
- #include "lookup.h"
- #include "translator.h"
- #include "object.h"
-
- /* Translate table block */
- static int level;
- static instn* block;
- static int blockLen;
-
- /*
- * Translate a method into native code.
- */
- void
- translate(methods* m)
- {
- instn* baseipc;
- instn* ipc;
- bytecode* pc;
- int i;
- int wide;
- int ret;
- bytecode* start;
- bytecode* end;
- int len;
- int offset;
- char* cname;
- int low;
- int high;
- int nargs;
- callInfo cinfo;
- createInfo crinfo;
- fieldInfo flinfo;
- tableswitch* table;
- lookupswitch* lookup;
- int adjust;
-
- /* First, if its native then dont do any of this stuff */
- if (m->accflags & ACC_NATIVE) {
- native(m);
- return;
- }
-
- start = m->code;
- assert(start != 0);
- len = m->codelen;
- assert(len > 0);
- nargs = m->ins;
- /* One extra argument for non-static methods */
- if (!(m->accflags & ACC_STATIC)) {
- nargs++;
- }
-
- level++;
- assert(level == 1);
-
- /* Reuse old block if we can */
- if (len < blockLen) {
- baseipc = block;
- }
- /* Otherwise allocate a new larger one */
- else {
- baseipc = (instn*)malloc(sizeof(instn) * len);
- if (baseipc == 0) {
- fprintf(stderr, "Insufficient translation space %d\n", len);
- level--;
- throwException(OutOfMemoryError);
- }
- if (block != 0) {
- free(block);
- }
- block = baseipc;
- blockLen = len;
- }
-
- m->insn = baseipc;
- pc = start;
- wide = 0;
- end = start + len;
-
- /* Mark out the instruction block with nulls initially. */
- for (i = 0; i < len; i++) {
- baseipc[i].type = i_null;
- baseipc[i].op = NOP;
- }
- baseipc[len - 1].type = i_endblock;
-
- /* Decode the instructions into the instruction block */
- for (pc = start; pc < end;) {
-
- ipc = &baseipc[pc - start];
- ipc->op = *pc++;
-
- switch (ipc->op) {
- case NOP:
- case ICONST_M1: case ACONST_NULL: case ICONST_0: case LCONST_0:
- case ICONST_1: case LCONST_1: case ICONST_2: case ICONST_3:
- case ICONST_4: case ICONST_5:
- case FCONST_0: case DCONST_0: case FCONST_1: case DCONST_1:
- case FCONST_2:
- case POP: case POP2: case SWAP:
- case DUP: case DUP_X1: case DUP_X2:
- case DUP2: case DUP2_X1: case DUP2_X2:
- case IADD: case LADD: case FADD: case DADD:
- case ISUB: case LSUB: case FSUB: case DSUB:
- case IMUL: case LMUL: case FMUL: case DMUL:
- case IDIV: case LDIV: case FDIV: case DDIV:
- case IREM: case LREM: case FREM: case DREM:
- case INEG: case LNEG: case FNEG: case DNEG:
- case ISHL: case LSHL: case ISHR: case LSHR:
- case IUSHR: case LUSHR: case IAND: case LAND:
- case IOR: case LOR: case IXOR: case LXOR:
- case I2L: case L2I: case I2F: case I2D:
- case L2F: case L2D: case F2I: case F2L:
- case F2D: case D2I: case D2L: case D2F:
- case INT2BYTE: case INT2CHAR: case INT2SHORT:
- case LCMP: case FCMPL: case FCMPG:
- case DCMPL: case DCMPG:
- case BREAKPOINT:
- case ATHROW:
- case MONITORENTER: case MONITOREXIT:
- break;
-
- case IRETURN: case LRETURN: case FRETURN:
- case DRETURN: case ARETURN: case RETURN:
- if (m->accflags & ACC_SYNCHRONISED) {
- if (m->accflags & ACC_STATIC) {
- ipc->value[0] = 0;
- ipc->value[1] = (int)m->class;
- }
- else {
- ipc->value[0] = LOCAL_FIXUP(0, nargs);
- ipc->value[1] = 0;
- }
- }
- else {
- ipc->value[0] = 0;
- ipc->value[1] = 0;
- }
- break;
-
- case IALOAD: case FALOAD: case AALOAD:
- case BALOAD: case CALOAD: case SALOAD:
- case IASTORE: case FASTORE: case AASTORE:
- case BASTORE: case CASTORE: case SASTORE:
- ipc->value[0] = OBJECT_DATA;
- break;
-
- case LALOAD: case DALOAD:
- case LASTORE: case DASTORE:
- ipc->value[0] = OBJECT_DATA;
- ipc->value[1] = OBJECT_DATA+4;
- break;
-
- case BIPUSH:
- ipc->value[0] = (int8)*pc++;
- break;
-
- case SIPUSH:
- ipc->value[0] = (int16)(256 * pc[0] + pc[1]);
- pc += 2;
- break;
-
- case LDC1:
- offset = *pc++;
- if (m->constants->tags[offset] == CONSTANT_Chararray) {
- makeStringObject(offset, m->constants);
- }
- ipc->value[0] = m->constants->data[offset];
- break;
-
- case LDC2:
- case LDC2W:
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- if (m->constants->tags[offset] == CONSTANT_Chararray) {
- makeStringObject(offset, m->constants);
- }
- ipc->value[0] = m->constants->data[offset];
- ipc->value[1] = m->constants->data[offset+1];
- break;
-
- case ILOAD: case ALOAD: case FLOAD:
- case ISTORE: case ASTORE: case FSTORE:
- offset = wide + *pc++;
- ipc->value[0] = LOCAL_FIXUP(offset, nargs);
- wide = 0;
- break;
-
- case LLOAD: case DLOAD: case LSTORE: case DSTORE:
- offset = wide + *pc++;
- ipc->value[0] = LOCAL_FIXUP(offset, nargs);
- ipc->value[1] = LOCAL_FIXUP(offset+1, nargs);
- wide = 0;
- break;
-
- case ILOAD_0: case FLOAD_0: case ALOAD_0:
- case ISTORE_0: case FSTORE_0: case ASTORE_0:
- ipc->value[0] = LOCAL_FIXUP(0, nargs);
- break;
-
- case LLOAD_0: case DLOAD_0:
- case LSTORE_0: case DSTORE_0:
- ipc->value[0] = LOCAL_FIXUP(0, nargs);
- ipc->value[1] = LOCAL_FIXUP(1, nargs);
- break;
-
- case ILOAD_1: case FLOAD_1: case ALOAD_1:
- case ISTORE_1: case FSTORE_1: case ASTORE_1:
- ipc->value[0] = LOCAL_FIXUP(1, nargs);
- break;
-
- case LLOAD_1: case DLOAD_1:
- case LSTORE_1: case DSTORE_1:
- ipc->value[0] = LOCAL_FIXUP(1, nargs);
- ipc->value[1] = LOCAL_FIXUP(2, nargs);
- break;
-
- case ILOAD_2: case FLOAD_2: case ALOAD_2:
- case ISTORE_2: case FSTORE_2: case ASTORE_2:
- ipc->value[0] = LOCAL_FIXUP(2, nargs);
- break;
-
- case LLOAD_2: case DLOAD_2:
- case LSTORE_2: case DSTORE_2:
- ipc->value[0] = LOCAL_FIXUP(2, nargs);
- ipc->value[1] = LOCAL_FIXUP(3, nargs);
- break;
-
- case ILOAD_3: case FLOAD_3: case ALOAD_3:
- case ISTORE_3: case FSTORE_3: case ASTORE_3:
- ipc->value[0] = LOCAL_FIXUP(3, nargs);
- break;
-
- case LLOAD_3: case DLOAD_3:
- case LSTORE_3: case DSTORE_3:
- ipc->value[0] = LOCAL_FIXUP(3, nargs);
- ipc->value[1] = LOCAL_FIXUP(4, nargs);
- break;
-
- case IINC:
- ipc->value[0] = LOCAL_FIXUP(pc[0], nargs);
- ipc->value[1] = (int8)pc[1];
- pc += 2;
- break;
-
- case IFEQ: case IFNE: case IFGE: case IFGT:
- case IFLT: case IFLE:
- case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT:
- case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE:
- case IF_ACMPEQ: case IF_ACMPNE:
- case IFNULL: case IFNONNULL:
- case GOTO: case JSR:
- ipc[0].type |= i_endblock;
- offset = (int16)(256 * pc[0] + pc[1]);
- ipc[0].value[0] = (pc - 1 - start) + offset;
- pc += 2;
- if (&ipc[offset] != &baseipc[0]) {
- assert(&ipc[offset-1] >= &baseipc[0]);
- assert(&ipc[offset-1] < &baseipc[len]);
- ipc[offset-1].type = i_endblock;
- }
- break;
-
- case GOTO_W: case JSR_W:
- ipc[0].type |= i_endblock;
- offset = (int32)(0x1000000*pc[0] + 0x10000*pc[1] + 0x100*pc[1] + pc[2]);
- ipc[0].value[0] = (pc - 1 - start) + offset;
- pc += 4;
- if (&ipc[offset] != &baseipc[0]) {
- assert(&ipc[offset-1] >= &baseipc[0]);
- assert(&ipc[offset-1] < &baseipc[len]);
- ipc[offset-1].type = i_endblock;
- }
- break;
-
- case RET:
- ipc->type |= i_endblock;
- offset = *pc++;
- ipc->value[0] = LOCAL_FIXUP(offset, nargs);
- break;
-
- case RET_W:
- ipc->type |= i_endblock;
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- ipc->value[0] = LOCAL_FIXUP(offset, nargs);
- break;
-
- case WIDE:
- wide = 256 * (*pc++);
- break;
-
- case INVOKEVIRTUAL:
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- getMethodSignatureClass(offset, m->constants, &cinfo);
- ipc->value[0] = cinfo.in * 4;
- ipc->value[1] = MTABLE_METHODOFFSET + MTABLE_METHODSIZE * (int)cinfo.offset;
- ipc->value[2] = ipc->value[1] + MTABLE_METHOD;
- ipc->value[3] = cinfo.mtag;
- /* Extra in argument is object itself */
- ipc->value[4] = (cinfo.in+1) * 4;
- /* Return arguments */
- ipc->value[7] = cinfo.out;
- break;
-
- case INVOKESTATIC:
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- getMethodSignatureClass(offset, m->constants, &cinfo);
- ipc->value[0] = (int)cinfo.mtable;
- ipc->value[1] = MTABLE_METHODOFFSET + MTABLE_METHODSIZE * (int)cinfo.offset;
- ipc->value[2] = ipc->value[1] + MTABLE_METHOD;
- ipc->value[3] = cinfo.mtag;
- ipc->value[4] = cinfo.in * 4;
- /* Return arguments */
- ipc->value[7] = cinfo.out;
- break;
-
- case INVOKENONVIRTUAL:
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- getMethodSignatureClass(offset, m->constants, &cinfo);
- ipc->value[0] = (int)cinfo.mtable;
- ipc->value[1] = MTABLE_METHODOFFSET + MTABLE_METHODSIZE * (int)cinfo.offset;
- ipc->value[2] = ipc->value[1] + MTABLE_METHOD;
- ipc->value[3] = cinfo.mtag;
- /* Extra in argument is object itself */
- ipc->value[4] = (cinfo.in+1) * 4;
- /* Return arguments */
- ipc->value[7] = cinfo.out;
- break;
-
- case INVOKEINTERFACE:
- offset = 256 * pc[0] + pc[1];
- low = pc[2];
- pc += 4; /* pc[3] is unused */
- getMethodSignatureClass(offset, m->constants, &cinfo);
- ipc->value[0] = (low - 1) * 4;
- ipc->value[1] = MTABLE_METHODOFFSET + MTABLE_METHODSIZE * (int)cinfo.offset;
- ipc->value[2] = ipc->value[1] + MTABLE_METHOD;
- ipc->value[3] = cinfo.mtag;
- ipc->value[4] = low * 4;
- /* Return arguments */
- ipc->value[7] = cinfo.out;
- break;
-
- case TABLESWITCH:
- ipc[0].type |= i_endblock;
- adjust = pc - 1 - start;
- pc = (bytecode*)((((uint32)pc) + 3) & -4);
- offset = 0x1000000*pc[0] + 0x10000*pc[1] + 0x100*pc[2] + pc[3];
- low = 0x1000000*pc[4] + 0x10000*pc[5] + 0x100*pc[6] + pc[7];
- high = 0x1000000*pc[8] + 0x10000*pc[9] + 0x100*pc[10] + pc[11];
- pc += 12;
-
- table = (tableswitch*)malloc(sizeof(tableswitch) + 4 * (high - low + 2));
- assert(table != 0);
- table->len = high - low + 2;
-
- if (&ipc[offset] != &baseipc[0]) {
- assert(&ipc[offset-1] >= &baseipc[0]);
- assert(&ipc[offset-1] < &baseipc[len]);
- ipc[offset-1].type = i_endblock;
- }
- table->offsets[high-low+1] = adjust + offset;
- for (i = 0; i < high - low + 1; i++) {
- offset = 0x1000000*pc[0] + 0x10000*pc[1] + 0x100*pc[2] + pc[3];
- if (&ipc[offset] != &baseipc[0]) {
- assert(&ipc[offset-1] >= &baseipc[0]);
- assert(&ipc[offset-1] < &baseipc[len]);
- ipc[offset-1].type = i_endblock;
- }
- table->offsets[i] = adjust + offset;
- pc += 4;
- }
- ipc->value[0] = (int)table->offsets;
- ipc->value[1] = low;
- ipc->value[2] = high - low + 1;
-
- table->next = m->tableswitches;
- m->tableswitches = table;
- break;
-
- case LOOKUPSWITCH:
- ipc[0].type |= i_endblock;
- adjust = pc - 1 - start;
- pc = (bytecode*)((((uint32)pc) + 3) & -4);
- offset = 0x1000000*pc[0] + 0x10000*pc[1] + 0x100*pc[2] + pc[3];
- low = 0x1000000*pc[4] + 0x10000*pc[5] + 0x100*pc[6] + pc[7];
- pc += 8;
-
- lookup = (lookupswitch*)malloc(sizeof(lookupswitch) + 8 * (low + 1));
- assert(lookup != 0);
- lookup->next = 0;
- lookup->len = low + 1;
-
- if (&ipc[offset] != &baseipc[0]) {
- assert(&ipc[offset-1] >= &baseipc[0]);
- assert(&ipc[offset-1] < &baseipc[len]);
- ipc[offset-1].type = i_endblock;
- }
- lookup->offsets[0] = 0;
- lookup->offsets[1] = adjust + offset;
- for (i = 1; i <= low; i++) {
- lookup->offsets[i*2] = 0x1000000*pc[0] + 0x10000*pc[1] + 0x100*pc[2] + pc[3];
- offset = 0x1000000*pc[4] + 0x10000*pc[5] + 0x100*pc[6] + pc[7];
- if (&ipc[offset] != &baseipc[0]) {
- assert(&ipc[offset-1] >= &baseipc[0]);
- assert(&ipc[offset-1] < &baseipc[len]);
- ipc[offset-1].type = i_endblock;
- }
- lookup->offsets[i*2+1] = adjust + offset;
- pc += 8;
- }
- ipc->value[0] = (int)&lookup->offsets[0];
- ipc->value[1] = (int)&lookup->offsets[low*2];
-
- lookup->next = m->lookupswitches;
- m->lookupswitches = lookup;
- break;
-
- case NEW:
- case ANEWARRAY:
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- getClass(offset, m->constants, &crinfo);
- ipc->value[0] = (int)crinfo.class;
- break;
-
- case MULTIANEWARRAY:
- offset = 256 * pc[0] + pc[1];
- ipc->value[1] = pc[2];
- ipc->value[3] = (ipc->value[1] + 1) * 4;
- pc += 3;
- getClass(offset, m->constants, &crinfo);
- ipc->value[0] = (int)crinfo.class;
- break;
-
- case GETSTATIC:
- offset = 256 * pc[0] + pc[1];
- getField(offset, true, m->constants, &flinfo);
- ipc->value[0] = ((int)flinfo.class->staticFields)
- + (4 * flinfo.offset);
- if (flinfo.size == 2) {
- ipc->value[1]= ((int)flinfo.class->staticFields)
- + (4 * (1 + flinfo.offset));
- ipc->op = GETSTATIC2_QUICK;
- }
- else {
- ipc->op = GETSTATIC_QUICK;
- }
- pc += 2;
- break;
-
- case PUTSTATIC:
- offset = 256 * pc[0] + pc[1];
- getField(offset, true, m->constants, &flinfo);
- ipc->value[0] = ((int)flinfo.class->staticFields)
- + (4 * flinfo.offset);
- if (flinfo.size == 2) {
- ipc->value[1]= ((int)flinfo.class->staticFields)
- + (4 * (1 + flinfo.offset));
- ipc->op = PUTSTATIC2_QUICK;
- }
- else {
- ipc->op = PUTSTATIC_QUICK;
- }
- pc += 2;
- break;
-
- case GETFIELD:
- offset = 256 * pc[0] + pc[1];
- getField(offset, false, m->constants, &flinfo);
- ipc->value[0] = OBJECT_DATA + 4 * flinfo.offset;
- if (flinfo.size == 2) {
- ipc->value[1] = ipc->value[0] + 4;
- ipc->op = GETFIELD2_QUICK;
- }
- else {
- ipc->op = GETFIELD_QUICK;
- }
- pc += 2;
- break;
-
- case PUTFIELD:
- offset = 256 * pc[0] + pc[1];
- getField(offset, false, m->constants, &flinfo);
- ipc->value[0] = OBJECT_DATA + 4 * flinfo.offset;
- if (flinfo.size == 2) {
- ipc->value[1] = ipc->value[0] + 4;
- ipc->op = PUTFIELD2_QUICK;
- }
- else {
- ipc->op = PUTFIELD_QUICK;
- }
- pc += 2;
- break;
-
- case CHECKCAST:
- case INSTANCEOF:
- offset = 256 * pc[0] + pc[1];
- pc += 2;
- getClass(offset, m->constants, &crinfo);
- ipc->value[0] = (int)crinfo.class;
- break;
-
- case NEWARRAY:
- ipc->value[0] = *pc++;
- break;
-
- case ARRAYLENGTH:
- ipc->value[0] = OBJECT_SIZE;
- break;
-
- default:
- fprintf(stderr, "Bad opcode %d\n", ipc->op);
- level--;
- throwException(VirtualMachineError);
- abort();
- }
- }
-
- /* Allocate registers */
- allocateRegisters(m);
-
- /* Translate */
- dumpInstn(m);
-
- /* Translate exception table */
- dumpExceptions(m);
-
- /* Translate switches */
- dumpSwitches(m);
-
- free(m->code);
- m->code = 0;
- m->insn = 0;
-
- /* Establish to method so it can take exceptions */
- establishMethod(m);
-
- level--;
- assert(level == 0);
- }
-