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
/
classMethod.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
12KB
|
598 lines
/*
* classMethod.c
* Dictionary of classes, methods and fields.
*
* 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.
*/
#define CDBG(s)
#define MDBG(s)
#define FDBG(s)
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "gtypes.h"
#include "slots.h"
#include "access.h"
#include "object.h"
#include "constants.h"
#include "classMethod.h"
#include "code.h"
#include "file.h"
#include "readClass.h"
#include "baseClasses.h"
#include "errors.h"
#include "exception.h"
extern strpair* initpair; /* Class init pair <clinit>()V */
extern strpair* finalpair; /* Class finalize pair finalize()V */
extern classes* classInitHead;
extern int classInitLevel;
static classes* classPool[CLASSHASHSZ];
methods* methodList; /* For exception processing */
void findClass(char*);
static classes* internalAddClass(char*, char*, int, char*, classes*, int, constants*);
classes*
addClass(constIndex c, constIndex s, u2 flags, constants* pool)
{
char* str;
char* sstr;
classes* su;
int basesize;
char sig[CLASSMAXSIG];
/* Find the name of the class */
if (pool->tags[c] != CONSTANT_Class) {
CDBG( printf("addClass: not a class.\n"); )
return (0);
}
c = pool->data[c].v.tint;
if (pool->tags[c] != CONSTANT_Utf8) {
CDBG( printf("addClass: not a Utf8.\n"); )
return (0);
}
str = pool->data[c].v.tstr;
assert(strlen(str) > 0);
/* Build signature */
if (str[0] != '[') {
strcpy(sig, "L");
strcat(sig, str);
strcat(sig, ";");
}
else {
strcpy(sig, str);
}
/* Find the name of the super class */
if (s != 0) {
if (pool->tags[s] != CONSTANT_Class) {
CDBG( printf("addClass: not a class.\n"); )
return (0);
}
s = pool->data[s].v.tint;
if (pool->tags[s] != CONSTANT_Utf8) {
CDBG( printf("addClass: not a Utf8.\n"); )
return (0);
}
sstr = pool->data[s].v.tstr;
/* Make sure it's loaded in */
su = lookupClass(sstr);
if (su == 0) {
return (0);
}
basesize = su->fsize;
}
else {
su = 0;
basesize = 0;
sstr = 0;
}
CDBG( printf("Adding class %s (%x)\n", str, flags); )
return (internalAddClass(str, addString(sig), flags, sstr, su, basesize, pool));
}
static
classes*
internalAddClass(char* str, char* sig, int flags, char* sstr, classes* su, int basesize, constants* pool)
{
classes** clp;
classes* cl;
methodTable* mt;
uint32 hash;
int i;
for (i = 0, hash = 0; str[i] != 0; i++) {
hash = hash * 33 + str[i];
}
hash %= CLASSHASHSZ;
clp = &classPool[hash];
#ifdef DEBUG
while (*clp != 0) {
assert(str != (*clp)->name);
clp = &(*clp)->next;
}
#endif
/* Allocate a class - it's an object too! */
cl = alloc_class();
if (cl == 0) {
return (0);
}
mt = (methodTable*)calloc(sizeof(methodTable), 1);
if (mt == 0) {
return (0);
}
mt->class = cl;
cl->name = str;
cl->sig = sig;
cl->supername = sstr;
cl->constants = pool;
cl->methodList = 0;
cl->fieldList = 0;
cl->staticFieldList = 0;
cl->superclass = su;
if (su == 0) {
cl->msize = 0;
}
else {
cl->msize = su->msize;
}
cl->fsize = basesize;
cl->sfsize = 0;
cl->accflags = flags;
cl->mtable = mt;
cl->dtable = 0;
cl->staticFields = 0;
cl->interfaces = 0;
cl->interface_len = 0;
cl->state = CSTATE_OK;
cl->final = false;
/* Add into list */
cl->next = *clp;
*clp = cl;
return (cl);
}
methods*
addMethod(classes* c, method_info* m)
{
constIndex nc;
constIndex sc;
methods** mptr;
methods* mt;
constants* pool;
strpair* pair;
int idx;
classes* spc;
pool = c->constants;
nc = m->name_index;
if (pool->tags[nc] != CONSTANT_Utf8) {
MDBG( printf("addMethod: no method name.\n"); )
return (0);
}
sc = m->signature_index;
if (pool->tags[sc] != CONSTANT_Utf8) {
MDBG( printf("addMethod: no signature name.\n"); )
return (0);
}
pair = addStringConstantPair(pool->data[nc].v.tstr, pool->data[sc].v.tstr);
assert(pair != 0);
/* Mark class for init if this is the class init method */
if (pair == initpair) {
c->state = CSTATE_NEEDINIT;
}
else if (pair == finalpair) {
c->final = true;
}
/* Search superclasses for equivalent method name. If found extract
* it's index nr.
*/
for (spc = c->superclass; spc != 0; spc = spc->superclass) {
for (mt = spc->methodList; mt != 0; mt = mt->next) {
if (mt->pair == pair) {
idx = mt->idx;
goto foundmatch;
}
}
}
/* No match found so allocate a new index number */
idx = c->msize;
c->msize++;
foundmatch:
mptr = &c->methodList;
#ifdef DEBUG
/* Search down class for method name - don't allow duplicates */
while (*mptr != 0) {
assert(pair != (*mptr)->pair);
mptr = &(*mptr)->next;
}
#endif
MDBG( printf("Adding method %s:%s%s (%x)\n", c->name, pool->data[nc].v.str, pool->data[sc].v.str, m->access_flags); )
mt = malloc(sizeof(methods));
if (mt == 0) {
return (0);
}
mt->pair = pair;
mt->class = c;
mt->accflags = m->access_flags;
mt->code = 0;
mt->insn = 0;
mt->ncode = 0;
mt->constants = pool;
mt->stacksz = 0;
mt->localsz = 0;
mt->exception_table = 0;
mt->exception_table_len = 0;
mt->exception_next = 0;
mt->idx = idx;
countInsAndOuts(pool->data[sc].v.tstr, &mt->ins, &mt->outs, &mt->outtype);
mt->next = *mptr;
*mptr = mt;
return (mt);
}
/*
* All class methods read in. Built the method dispatch table.
*/
void
finishClassMethods(classes* c)
{
dispatchTable* tab;
tab = (dispatchTable*)calloc(sizeof(dispatchTable) + (c->msize * sizeof(void*)), 1);
assert(tab != 0);
tab->class = c;
tab->mtable = c->mtable;
c->dtable = tab;
}
fields*
addField(classes* c, field_info* f)
{
constIndex nc;
constIndex sc;
fields** fptr;
fields* ft;
char* sig;
constants* pool;
int* optr;
pool = c->constants;
nc = f->name_index;
if (pool->tags[nc] != CONSTANT_Utf8) {
FDBG( printf("addField: no field name.\n"); )
return (0);
}
/* Search down class for field name */
if (f->access_flags & ACC_STATIC) {
fptr = &c->staticFieldList;
optr = &c->sfsize;
}
else {
fptr = &c->fieldList;
optr = &c->fsize;
}
#ifdef DEBUG
while (*fptr != 0) {
assert(pool->data[nc].v.tstr != (*fptr)->name);
fptr = &(*fptr)->next;
}
#endif
FDBG( printf("Adding field %s:%s\n", c->name, pool->data[nc].v.tstr); )
sc = f->signature_index;
if (pool->tags[sc] != CONSTANT_Utf8) {
FDBG( printf("addField: no signature name.\n"); )
return (0);
}
sig = pool->data[sc].v.tstr;
ft = malloc(sizeof(fields));
if (ft == 0) {
return (0);
}
ft->name = pool->data[nc].v.tstr;
ft->sig = sig;
ft->class = c;
ft->accflags = f->access_flags;
ft->size = sizeofSig(&sig);
/* Align field offset */
if (((*optr) % ft->size) == 1) {
(*optr)++;
}
ft->offset = *optr;
(*optr) += ft->size;
ft->next = *fptr;
*fptr = ft;
return (ft);
}
void
addMethodCode(methods* m, Code* c)
{
m->code = c->code;
m->codelen = c->code_length;
m->stacksz = c->max_stack;
m->localsz = c->max_locals;
m->exception_table = c->exception_table;
m->exception_table_len = c->exception_table_length;
}
void
addInterfaces(classes* c, int inr, classes** inf)
{
assert(inr > 0);
c->interfaces = inf;
c->interface_len = inr;
}
/*
* Lookup a named class, loading it if necessary.
*/
classes*
lookupClass(char* c)
{
classes* class;
class = simpleLookupClass(c);
if (class == 0) {
/* Failed to find class, so must now load it */
findClass(c);
/* Once loaded, allocate the static data space */
class = simpleLookupClass(c);
if (class == 0) {
throwException(ClassNotFoundException);
}
if (class->sfsize > 0) {
class->staticFields = (int*)calloc(class->sfsize, sizeof(int));
assert(class->staticFields != 0);
}
}
/* This class requires initialisation so place it at head of
current init list. If already at head of an init list (not this
one), then we have a recursive init which is an error */
if (class->state == CSTATE_OK || class->state == classInitLevel) {
/* Do nothing. */
}
else {
assert(class->state <= classInitLevel);
/* If already on a list, remove it */
if (class->state != CSTATE_NEEDINIT) {
if (class->prevInit == 0) {
throwException(ClassCircularityError);
}
class->prevInit->nextInit = class->nextInit;
if (class->nextInit != 0) {
class->nextInit->prevInit = class->prevInit;
}
}
/* Insert onto current list */
class->state = classInitLevel;
class->prevInit = 0;
class->nextInit = classInitHead;
if (classInitHead) {
classInitHead->prevInit = class;
}
classInitHead = class;
#if defined(INTERPRETER)
/* We must do this as we go along when interpreting */
initClasses();
#endif
}
return (class);
}
classes*
simpleLookupClass(char* c)
{
uint32 hash;
char* str;
classes* clp;
for (str = c, hash = 0; *str != 0; str++) {
hash = hash * 33 + *str;
}
hash %= CLASSHASHSZ;
clp = classPool[hash];
while (clp != 0) {
if (c == clp->name) {
return (clp);
}
clp = clp->next;
}
return (0);
}
/*
* Lookup a named field.
*/
fields*
lookupClassField(char* c, char* f, bool isStatic)
{
classes* clp;
fields* fptr;
/* Look for class */
clp = lookupClass(c);
if (clp == 0) {
return (0);
}
/* Search down class for field name */
if (isStatic) {
fptr = clp->staticFieldList;
}
else {
fptr = clp->fieldList;
}
while (fptr != 0) {
if (f == fptr->name) {
return (fptr);
}
fptr = fptr->next;
}
FDBG( printf("Class:field lookup failed %s:%s\n", c, f); )
return (0);
}
/*
* Determine the number of arguments and return values from the
* method signature.
*/
void
countInsAndOuts(char* str, int* ins, int* outs, char* outtype)
{
*ins = sizeofSig(&str);
*outtype = str[0];
*outs = sizeofSig(&str);
}
/*
* Calculate size of data item based on signature.
*/
int
sizeofSig(char** strp)
{
int count;
int c;
count = 0;
for (;;) {
c = sizeofSigItem(strp, 0);
if (c == -1) {
return (count);
}
count += c;
}
}
/*
* Calculate size of a signature item.
*/
int
sizeofSigItem(char** strp, char* sig)
{
int count;
char* str;
for (str = *strp; ; str++) {
/* Return sig if requested */
if (sig != 0) {
*sig = *str;
}
switch (*str) {
case '(':
continue;
case 0:
case ')':
count = -1;
break;
case 'V':
count = 0;
break;
case 'I':
case 'Z':
case 'S':
case 'B':
case 'C':
case 'F':
count = 1;
break;
case 'D':
case 'J':
count = 2;
break;
case '[':
count = 1;
arrayofarray:
str++;
if (*str == 'L') {
while (*str != ';') {
str++;
}
}
else if (*str == '[') {
goto arrayofarray;
}
break;
case 'L':
count = 1;
/* Skip to end of reference */
while (*str != ';') {
str++;
}
break;
default:
abort();
}
*strp = str + 1;
return (count);
}
}
/*
* Add this method to the method list so we can find it when
* handling exceptions.
*/
void
establishMethod(methods* m)
{
m->exception_next = methodList;
methodList = m;
}
/*
* Lookup an array class.
*/
classes*
lookupArray(char* c)
{
classes* class;
class = simpleLookupClass(c);
if (class == 0) {
class = internalAddClass(c, c, 0, ObjectClassName, ObjectClass, 0, 0);
CDBG( if (class == 0) {
printf("Array Class %s not loaded.\n", c);
} )
finishClassMethods(class);
}
return (class);
}