home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
kaffe-0.5p4-src.tgz
/
tar.out
/
contrib
/
kaffe
/
kaffevm
/
jit
/
machine.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
12KB
|
552 lines
/* machine.c
* Translate the Kaffe instruction set to the native one.
*
* 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>, June 1996.
*/
#define DBG(s)
#define BDBG(s)
#define MDBG(s)
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "gtypes.h"
#include "bytecode.h"
#include "slots.h"
#include "registers.h"
#include "seq.h"
#include "machine.h"
#include "basecode.h"
#include "icode.h"
#include "labels.h"
#include "codeinfo.h"
#include "codeproto.h"
#include "checks.h"
#include "access.h"
#include "object.h"
#include "constants.h"
#include "baseClasses.h"
#include "classMethod.h"
#include "access.h"
#include "lookup.h"
#include "exception.h"
#include "ops.h"
#include "gc.h"
#include "flags.h"
#include "md.h"
int code_size;
codes* code;
int stackno;
int maxStack;
int maxLocal;
int maxTemp;
int maxArgs;
int isStatic;
callInfo cinfo;
fieldInfo flinfo;
createInfo crinfo;
/* Fix to so we can reuse libraries without change */
slots retarg;
int tmpslot = 0;
int argcount = 0; /* Function call argument count */
uint32 pc;
uint32 npc;
/* Unit in which code block is increased when overrun */
#define ALLOCCODEBLOCKSZ 8192
/* Codeblock redzone - allows for safe overrun when generating instructions */
#define CODEBLOCKREDZONE 256
static nativecode* codeblock;
static int codeblock_size;
nativecode* CODEPC;
uintp realcodediff;
static void findBlocks(methods*, uint32, int);
static void generateCode(methods*);
void endBlock(sequence*);
void startBlock(sequence*);
/*
* Translate a method into native code.
*/
void
translate(methods* meth)
{
uint32 wide;
int i;
jint low;
jint high;
int idx;
slots* cnst;
slots* tmp;
slots* tmp2;
slots* mtable;
bytecode* base;
int len;
DBG( printf("callinfo = 0x%x\n", &cinfo); )
/* If this code block is native, then just set it up and return */
if ((meth->accflags & ACC_NATIVE) != 0) {
native(meth);
return;
}
maxLocal = meth->localsz;
maxStack = meth->stacksz;
maxArgs = meth->ins;
if (meth->accflags & ACC_STATIC) {
isStatic = 1;
}
else {
isStatic = 0;
maxArgs += 1;
}
base = (bytecode*)meth->code;
len = meth->codelen;
/* Make sure we have enough code space */
if (len+1 > code_size) {
if (code != 0) {
free(code);
}
code = calloc(sizeof(codes), len+1);
assert(code != 0);
code_size = len+1;
}
/* Set locals, stack and temps */
assert(maxLocal + maxStack < MAXSLOT);
localinfo = &slotinfo[0];
stackinfo = &localinfo[maxLocal];
tempinfo = &stackinfo[maxStack];
initSeq();
initRegisters();
initSlots();
/* Traverse code block to mark branch and join points */
for (i = 0; i < len; i++) {
code[i].block = 0;
code[i].stackdepth = -1;
code[i].pc = (uintp)-1;
}
stackval(len) = MAXSLOT;
/* Scan the code and determine the basic blocks */
/* First the main body of code. */
findBlocks(meth, 0, 0);
/* Then the exception handlers */
for (i = 0; i < meth->exception_table_len; i++) {
findBlocks(meth, meth->exception_table[i].handler_pc, 1);
BLOCKPOINT(meth->exception_table[i].handler_pc) |= IEBSTART;
}
/* Clear temporary counter */
maxTemp = 0;
/* Next reduce bytecode to native code */
start_function();
monitor_enter();
npc = 0;
wide = 0;
start_basic_block();
for (pc = 0; pc < len; pc = npc) {
/* If this is -1 then this code was unreachable - skip it */
if (stackval(pc) == -1) {
npc = pc + 1;
continue;
}
/* Retrieve stack for new instruction and next instruction
* pointer.
*/
stackno = meth->stacksz - stackval(pc);
assert(stackno >= 0);
assert(stackno <= meth->stacksz);
npc = pc + opcodeInfo[base[pc]].len;
/* Note start of exception handling blocks */
if (BLOCKPOINT(pc) & IEBSTART) {
start_exception_block();
}
start_instruction();
switch (base[pc]) {
default:
fprintf(stderr, "Unknown bytecode %d\n", base[pc]);
abort();
#include "kaffe.def"
}
/* Note maximum number of temp slots used and reset it */
if (tmpslot > maxTemp) {
maxTemp = tmpslot;
}
tmpslot = 0;
if (BLOCKPOINT(npc) & IBBSTART) {
end_basic_block();
start_basic_block();
}
}
assert(maxLocal + maxStack + maxTemp < MAXSLOT);
/* Generate and link code */
generateCode(meth);
establishMethod(meth);
MDBG( printf("Translating %s.%s%s (%s) 0x%x\n", meth->class->name, meth->pair->s1, meth->pair->s2, isStatic ? "static" : "normal", meth->ncode); )
}
/*
* Analyse code to work out basic blocks and stack depths.
*/
static
void
findBlocks(methods* meth, uint32 pc, int stk)
{
uint32 destpc;
uint32 tabpc;
uint32 idx;
uint32 low;
uint32 high;
bytecode* base;
base = (bytecode*)meth->code;
/* Mark start of basic block */
BLOCKPOINT(pc) = IBBSTART;
while (stackval(pc) == -1) {
assert(stk >= 0 && stk <= meth->stacksz);
stackval(pc) = stk;
if (opcodeInfo[base[pc]].stack == 9) {
idx = (base[pc+1] << 8)|base[pc+2];
/* Variable length ones */
switch (base[pc]) {
case INVOKEVIRTUAL:
case INVOKENONVIRTUAL:
case INVOKEINTERFACE:
getMethodSignatureClass(idx, meth->constants, &cinfo);
stk -= cinfo.in + 1;
stk += cinfo.out;
break;
case INVOKESTATIC:
idx = (base[pc+1] << 8)|base[pc+2];
getMethodSignatureClass(idx, meth->constants, &cinfo);
stk -= cinfo.in;
stk += cinfo.out;
break;
case GETFIELD:
getField(idx, false, meth->constants, &flinfo);
stk += flinfo.size - 1;
break;
case PUTFIELD:
getField(idx, false, meth->constants, &flinfo);
stk -= flinfo.size + 1;
break;
case GETSTATIC:
getField(idx, true, meth->constants, &flinfo);
stk += flinfo.size;
break;
case PUTSTATIC:
getField(idx, true, meth->constants, &flinfo);
stk -= flinfo.size;
break;
case MULTIANEWARRAY:
stk -= (uint8)base[pc+3] - 1;
break;
default:
abort();
}
}
else {
stk += opcodeInfo[base[pc]].stack;
}
switch (opcodeInfo[base[pc]].jmp) {
case 1:
switch (opcodeInfo[base[pc]].len) {
case 3:
destpc = pc + (int16)
(base[pc+1] * 0x00000100 +
base[pc+2] * 0x00000001);
findBlocks(meth, destpc, stk);
break;
case 5:
destpc = pc + (int32)
(base[pc+1] * 0x01000000 +
base[pc+2] * 0x00010000 +
base[pc+3] * 0x00000100 +
base[pc+4] * 0x00000001);
findBlocks(meth, destpc, stk);
break;
default:
abort();
break;
}
pc += opcodeInfo[base[pc]].len;
/* Mark start of basic block */
BLOCKPOINT(pc) = IBBSTART;
break;
case 2: /* Returns */
return;
case 3: /* Gotos */
switch (opcodeInfo[base[pc]].len) {
case 3:
pc = pc + (int16)
(base[pc+1] * 0x00000100 +
base[pc+2] * 0x00000001);
break;
case 5:
pc = pc + (int32)
(base[pc+1] * 0x01000000 +
base[pc+2] * 0x00010000 +
base[pc+3] * 0x00000100 +
base[pc+4] * 0x00000001);
break;
case 0:
/* Table and Switch */
tabpc = pc + 4 - (pc % 4);
if (base[pc] == LOOKUPSWITCH) {
idx = (uint32)
(base[tabpc+4] * 0x01000000 +
base[tabpc+5] * 0x00010000 +
base[tabpc+6] * 0x00000100 +
base[tabpc+7] * 0x00000001);
for (; idx > 0; idx--) {
destpc = pc + (int32)
(base[tabpc+idx*8+4] * 0x01000000 +
base[tabpc+idx*8+5] * 0x00010000 +
base[tabpc+idx*8+6] * 0x00000100 +
base[tabpc+idx*8+7] * 0x00000001);
findBlocks(meth, destpc, stk);
}
pc = pc + (int32)
(base[tabpc+0] * 0x01000000 +
base[tabpc+1] * 0x00010000 +
base[tabpc+2] * 0x00000100 +
base[tabpc+3] * 0x00000001);
}
else {
assert(base[pc] == TABLESWITCH);
low = (uint32)
(base[tabpc+4] * 0x01000000 +
base[tabpc+5] * 0x00010000 +
base[tabpc+6] * 0x00000100 +
base[tabpc+7] * 0x00000001);
high = (uint32)
(base[tabpc+8] * 0x01000000 +
base[tabpc+9] * 0x00010000 +
base[tabpc+10] * 0x00000100 +
base[tabpc+11] * 0x00000001);
for (idx = 0; idx < high-low+1; idx++) {
destpc = pc + (int32)
(base[tabpc+idx*4+12] * 0x01000000 +
base[tabpc+idx*4+13] * 0x00010000 +
base[tabpc+idx*4+14] * 0x00000100 +
base[tabpc+idx*4+15] * 0x00000001);
findBlocks(meth, destpc, stk);
}
pc = pc + (int32)
(base[tabpc+0] * 0x01000000 +
base[tabpc+1] * 0x00010000 +
base[tabpc+2] * 0x00000100 +
base[tabpc+3] * 0x00000001);
}
break;
}
/* Mark start of basic block */
BLOCKPOINT(pc) = IBBSTART;
break;
case 0:
pc += opcodeInfo[base[pc]].len;
break;
default:
abort();
break;
}
}
if (stk != stackval(pc) && stackval(pc) != MAXSLOT) {
fprintf(stderr, "Stack depths wrong at %d (code=0x%x)\n", pc, &code);
abort();
}
}
/*
* Generate the code.
*/
static
void
generateCode(methods* meth)
{
sequence* t;
uint32 clen;
nativecode* realcode;
int i;
jexception* e;
DBG( printf("codeblock = 0x%x\n", codeblock); )
DBG( printf("slotinfo = 0x%x\n", slotinfo); )
restart:
CODEPC = codeblock;
for (t = firstSeq; t != currSeq; t = t->next) {
/* If we overrun the codeblock, reallocate and restart */
if (CODEPC >= &codeblock[codeblock_size]) {
if (codeblock != 0) {
free(codeblock);
}
codeblock_size += ALLOCCODEBLOCKSZ;
codeblock = calloc(sizeof(nativecode), codeblock_size + CODEBLOCKREDZONE);
assert(codeblock != 0);
goto restart;
}
/* Generate sequences which are actually referenced */
if (t->ref > 0) {
(*(t->func))(t);
}
}
/* Okay, put this into malloc'ed memory */
clen = CODEPC - codeblock;
realcode = malloc(clen);
assert(realcode != 0);
memcpy(realcode, codeblock, clen);
/* Link it */
realcodediff = realcode - codeblock;
linkLabels();
/* Note where it all is */
meth->ncode = realcode;
meth->ncode_end = realcode + clen;
/* Translate exception table and make it available */
if (meth->exception_table != 0) {
for (i = 0; i < meth->exception_table_len; i++) {
e = &meth->exception_table[i];
e->start_pc = code[e->start_pc].pc + realcodediff;
e->end_pc = code[e->end_pc].pc + realcodediff;
e->handler_pc = code[e->handler_pc].pc + realcodediff;
}
}
}
/*
* Start a new instruction.
*/
void
startInsn(sequence* s)
{
uintp pc;
/* Note PC value at start of this instruction */
pc = const_int(2);
code[pc].pc = (uintp)CODEPC;
}
/*
* Invalidate a specific slot to avoid writeback.
*/
void
invalSlot(sequence* s)
{
seq_slot(s, 2)->modified = 0;
}
/*
* Start a new basic block.
*/
void
startBlock(sequence* s)
{
int i;
startInsn(s);
/* Invalidate all slots - don't use clobberRegister which will
* flush them - we do not want to do that even if they are dirty.
*/
for (i = MAXSLOT - 1; i >= 0; i--) {
if (slotinfo[i].regno != NOREG) {
register_invalidate(slotinfo[i].regno);
slot_invalidate(&slotinfo[i]);
}
}
BDBG( printf("-------start-------\n"); )
}
/*
* End a basic block.
*/
void
endBlock(sequence* s)
{
int stkno;
int i;
/* Spill locals */
for (i = 0; i < maxLocal; i++) {
if ((localinfo[i].modified & rwrite) != 0 && localinfo[i].regno != NOREG) {
spill(&localinfo[i]);
}
}
/* Spill stack */
stkno = const_int(1);
for (i = stkno; i < maxStack; i++) {
if ((stackinfo[i].modified & rwrite) != 0 && stackinfo[i].regno != NOREG) {
spill(&stackinfo[i]);
}
}
/* Spill temps currently in use */
tmpslot = const_int(2);
for (i = 0; i < tmpslot; i++) {
if ((tempinfo[i].modified & rwrite) != 0 && tempinfo[i].regno != NOREG) {
spill(&tempinfo[i]);
}
}
BDBG( printf("-------end-------\n"); )
}