// Date: 09/02/02
// Name: Vijay P. Chauhan
// Supervisor: Dr. Arthur Norman
// "Jlisp to JVM Compiler" - Part II Project
//
// 21/02/02
// ClassDescription4.java for using with jlisp to make LengthFn.class
// ClassDescription3.java THIS IS FOR getting resolveAll() to work
// ClassDescription2.java works fine (with one cheat).
// resolveAll wasn't working because I was casting to Code_attribute
// needed to access attribute[].info with offset 8(maxstack,locals,length,etc)
// Class File format (.class) mapped out according to JVM spec
// map structure -> byte[] -> written to file (.class)
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
public class ClassDescription
{
// all access flags included for COMPLETENESS even though not all used
public static final short ACC_DEFAULT = 0x0000;
public static final short ACC_PUBLIC = 0x0001;
public static final short ACC_PRIVATE = 0x0002;
public static final short ACC_PROTECTED = 0x0004;
public static final short ACC_STATIC = 0x0008;
public static final short ACC_FINAL = 0x0010;
public static final short ACC_SYNCHRONIZED = 0x0020;
public static final short ACC_SUPER = 0x0020;
public static final short ACC_VOLATILE = 0x0040;
public static final short ACC_TRANSIENT = 0x0080;
public static final short ACC_NATIVE = 0x0100;
public static final short ACC_INTERFACE = 0x0200;
public static final short ACC_ABSTRACT = 0x0400;
public static final short ACC_STRICT = 0x0800;
// check if versions supported by jdk1.4.0 beta3
// Note that I REALLY HOPE that the code here is not sensitive to
// just which release of Java is in use. Thre is no good reason why
// it should be!
static final int MAGIC = 0xcafebabe;
static final short minor_version = 0x0;
static final short major_version = 0x2e;
short constant_pool_count = 0;
Cp_info constant_pool[];
short access_flags;
short this_class; //= 14
short super_class; //= 7
short interfaces_count = 0; // counts are initialised to 0
short interfaces[]; //should be [interfaces_count]
short fields_count = 0;
Field_info fields[]; //should be [fields_count]
short methods_count = 0;
Method_info methods[]; //should be [methods_count]
short attributes_count = 0; //LineNumberTable, SourceFile not implmtd
Attribute_info attributes[] ; //should be [attributes_count]
//NOT part of classfile structure -> see VM spec for above
String thisString;
String superString = "java/lang/Object";
String init = "<init>";
String code = "Code";
String exceptions_attribute = "Exceptions";
String exception = "java/lang/Exception";
short this_Utf8, super_Utf8, code_Utf8;
short globalIndex;
short initNAT, initref; //for holding reference to methodref_info for <init>
Exceptions_attribute ea = new Exceptions_attribute();
byte[] ClassBytes;
// note from ACN to VPC. There is a Java tradition of naming little
// methods that just set a field xxx as setxxx.
void mNumber(int a) //number of methods defined in the class
//N.B. which is NOT necessarily equal to number of methodref_infos
{ methods = new Method_info[a];
}
void setAccess(short access)
{ access_flags = access;
}
void addCode() throws IOException
{ addUtf8(code);
code_Utf8 = globalIndex;
} //put "Code" for Code_attribute in cp[1] since cp[0] is null
void addExceptions() throws IOException
{ addUtf8(exceptions_attribute);
//put "Exceptions" for Exceptions_attribute in cp[2]
ea.attribute_name_index = globalIndex;
//put "java/lang/Exception" in cp[3]
addUtf8(exception);
addCInfo(globalIndex);
ea.exception_index_table[0] = globalIndex;
ea.toInfo();
}
void setThis(String thisName)
throws UnsupportedEncodingException,
IOException
{ thisString = thisName;
addUtf8(thisName); //add CONSTANT_Utf8_info
this_Utf8 = globalIndex;
addCInfo(this_Utf8); //add CONSTANT_Class_info
this_class = globalIndex;
// put thisName in ConstantPool and then set this_class
}
void setSuper() throws UnsupportedEncodingException, IOException
{ addUtf8(superString); //add CONSTANT_Utf8_info
super_Utf8 = globalIndex;
addCInfo(super_Utf8); //add CONSTANT_Class_info
super_class = globalIndex;
//if no argument given then default superclass is java.lang.Object
}
void setSuper(String superName)
throws UnsupportedEncodingException, IOException
{ superString = superName;
addUtf8(superString); //add CONSTANT_Utf8_info
super_Utf8 = globalIndex;
addCInfo(super_Utf8); //add CONSTANT_Class_info
super_class = globalIndex;
// put superString in ConstantPool
}
void addInit(Method_info m1) throws IOException
// how to add <init>, ()V since needed for every class
{
m1.setAccess((short)ACC_PUBLIC); // ACC_PUBLIC in some cases?
//make <init> PUBLIC by default
lookupUtf8(init); // DO NOT ASSUME THERE IS ONLY 1 "<init>" made.
if (utf8Index == 0) // not made so far
{ addUtf8(init); // then make it
m1.name_index = globalIndex;
}
else m1.name_index = utf8Index;
addUtf8("()V"); //"()V"
m1.descriptor_index = globalIndex;
addNAT(m1);
initNAT = globalIndex;
//addCInfo(super_Utf8); //invoked from super_class (whatever it is)
//super_class = globalIndex; //7
addCMInfo(super_class, initNAT);
initref = globalIndex;
/*
addUtf8("<init>"); //"<init>"
m1.name_index = globalIndex; //4
addUtf8("()V"); //"()V"
m1.descriptor_index = globalIndex; //5
addNAT(m1);
NATindex = globalIndex; //6
//addCInfo(super_Utf8); //invoked from super_class (whatever it is)
//super_class = globalIndex; //7
addCMInfo(super_class, NATindex);
*/
// m1.attributes_count = (short)1; fixed in Method_info.java
Code_attribute ca1 = new Code_attribute();
ca1.attribute_name_index = code_Utf8;
ca1.setStackLocals((short)1,(short)1);
ca1.addInstruction(ByteCodes.ALOAD_0);
//lookupRef("<init>", ca1); //no need to lookup really? save time?
//byte[] arg1 = ByteArray.shortToByteArray(methodrefIndex[0]);//{0x00, 0x08}; //cp[8]
//byte[] arg1 = ByteArray.shortToByteArray(refIndex);
byte[] arg1 = ByteArray.shortToByteArray(initref);
ca1.addInstruction(ByteCodes.INVOKESPECIAL, arg1);
ca1.addInstruction(ByteCodes.RETURN);
ca1.toInfo();
m1.attributes = new Attribute_info[m1.attributes_count];
m1.attributes[0] = ca1;
methods[methods_count++] = m1;
}
void addMethod(Method_info m3, String methodName, String methodDesc)
throws IOException
// makes Methodref_info irrespective -> see other addMethod(...,boolean b)
{
//m3.setAccess((short)(ClassDescription4.ACC_STATIC));
addUtf8(methodName);
m3.name_index = globalIndex;
addUtf8(methodDesc); // argument and result types, eg "(I)I"
m3.descriptor_index = globalIndex;
addNAT(m3);
//addCInfo(this_Utf8); // NOT super_class but this_class
//any method after <init> (not 'main') has this_class as class_index
//this_class = globalIndex;
addCMInfo(this_class, globalIndex);
}
void addMethod(Method_info m3,
String methodName,
String methodDesc,
boolean b) throws IOException
// if (b==true) then it means we do want a Methodref too, otherwise not
{ addUtf8(methodName);
m3.name_index = globalIndex;
addUtf8(methodDesc); // eg "(I)I"
m3.descriptor_index = globalIndex;
if (b)
{ addNAT(m3);
addCMInfo(this_class, globalIndex);
}
}
Vector cptemp = new Vector(20,10); //default size 20, increment 10 if full.
//change to more appropriate numbers depending on likely cp size.
//process of incrementing takes time (see Java 2-Ivor Horton, pg 410).
//possible optimisation HERE
void addMethodref(String cl, String nm, String des) throws IOException
{ short nmidx;
short desidx;
Code_attribute ca = new Code_attribute();
lookupCinfo(cl,ca, false); // don't want to add to toResolveClass list
if (cinfoIndex == 0) // if no class entry by this name..
{ addUtf8(cl); // ..then create one
addCInfo(globalIndex);
cinfoIndex = globalIndex;
}
lookupUtf8(nm);
if (utf8Index == 0) // not made so far
{ addUtf8(nm); // then make it
nmidx = globalIndex;
}
else nmidx = utf8Index;
lookupUtf8(des);
if (utf8Index == 0) // not made so far
{ addUtf8(des); // then make it
desidx = globalIndex;
}
else desidx = utf8Index;
if (!isNAT(nmidx, desidx))
{ addNAT(nmidx, desidx);
addCMInfo(cinfoIndex, globalIndex);
}
else
if (!isRef(cinfoIndex, nameAndTypeIndex))
{ addCMInfo(cinfoIndex, nameAndTypeIndex); }
// else System.out.print("**************NO NEED TO MAKE MREF");
utf8Index = 0;
nameAndTypeIndex = 0;
cinfoIndex = 0; // before anyone else uses this value again
}
void addFieldref(String cl, String nm, String des) throws IOException
{ short nmidx;
short desidx;
Code_attribute ca = new Code_attribute();
lookupCinfo(cl,ca, false); // don't want to add to toResolveClass list
if (cinfoIndex == 0) // if no class entry by this name..
{ addUtf8(cl); // ..then create one
addCInfo(globalIndex);
cinfoIndex = globalIndex;
}
lookupUtf8(nm);
if (utf8Index == 0) // not made so far
{ addUtf8(nm); // then make it
nmidx = globalIndex;
}
else nmidx = utf8Index;
lookupUtf8(des);
if (utf8Index == 0) // not made so far
{ addUtf8(des); // then make it
desidx = globalIndex;
}
else desidx = utf8Index;
if (!isNAT(nmidx, desidx))
{ addNAT(nmidx, desidx);
addCFInfo(cinfoIndex, globalIndex);
}
else
if (!isRef(cinfoIndex, nameAndTypeIndex))
{ addCFInfo(cinfoIndex, nameAndTypeIndex); }
//else System.out.print("**************NO NEED TO MAKE FREF")
utf8Index = 0;
nameAndTypeIndex = 0;
cinfoIndex = 0; // before anyone else uses this value again
}
void addClassInfo(String cl)throws IOException
{ Code_attribute ca = new Code_attribute();
lookupCinfo(cl,ca,false);
if (cinfoIndex == 0) // if no class entry by this name..
{ addUtf8(cl); // ..then create one
addCInfo(globalIndex);
}
}
void addCFInfo(short classindex, short NATindex) throws IOException
{ CONSTANT_Fieldref_info cf =
new CONSTANT_Fieldref_info(classindex, NATindex);
addToCP(cf);
}
void addCMInfo(short classindex, short NATindex) throws IOException
{ CONSTANT_Methodref_info cm =
new CONSTANT_Methodref_info(classindex, NATindex);
addToCP(cm);
}
void addCInfo(short classindex) throws IOException
{ CONSTANT_Class_info ci = new CONSTANT_Class_info(classindex);
addToCP(ci);
}
void addNAT(short nidx, short didx) throws IOException
// if Methodref/Fieldref_info not associated with declared method/field
{ CONSTANT_NameAndType_info cnt =
new CONSTANT_NameAndType_info(nidx, didx);
addToCP(cnt);
}
void addNAT(Method_info m) throws IOException
// NEED one for Field_info? in future maybe if Field_info needed.
{ CONSTANT_NameAndType_info cnt =
new CONSTANT_NameAndType_info(m.name_index, m.descriptor_index);
addToCP(cnt);
}
void addUtf8(String s) throws IOException
{ CONSTANT_Utf8_info cu = new CONSTANT_Utf8_info(s);
addToCP(cu);
}
void addToCP(Cp_info c)
{ cptemp.add(c);
globalIndex = (short)(cptemp.indexOf(c)+1);
//very important: globalIndex
//or just do globalIndex++ ?
//+1 because CP entries start from cp[1], not from cp[0]
}
Vector labels = new Vector();
Vector positions = new Vector();
Vector mcountsL = new Vector();
Vector labelToLookup = new Vector();
Vector positionToPut = new Vector();
void setLabel(String label, Code_attribute ca)
{
labels.add(label);
Integer pointer = new Integer(ca.code.length);
positions.add(pointer);
Short methodIndex = new Short(methods_count);
mcountsL.add(methodIndex);
}
void lookupLabel(String label, Code_attribute ca)
{
labelToLookup.add(label);
Integer pointer = new Integer(ca.code.length+1);
positionToPut.add(pointer); //because GOTO or IF_CMP instr not yet added
}
void resolveLabels() //only one pass overall
{
for (int i=0; i<labelToLookup.size(); i++)
{ for (int j=0; j<labels.size(); j++)
{ if (labelToLookup.get(i) == labels.get(j))
{
//Jlisp.println("i = " + i + " j = " + j);
//Jlisp.println(positions.size() + " " + positionToPut.size() + " " +
//mcountsL.size() + " " + methods.length);
int offset = ((Integer)positions.get(j)).intValue()
- ((Integer)positionToPut.get(i)).intValue() + 1;
byte[] bytesoffset = ByteArray.shortToByteArray((short)offset);
int pointer = ((Integer)positionToPut.get(i)).intValue();
short methodIndex = ((Short)mcountsL.get(j)).shortValue();
// ACN changed the above from i to j ^
(methods[methodIndex].attributes[0]).info[pointer+8]=bytesoffset[0];
(methods[methodIndex].attributes[0]).info[pointer+8+1]=bytesoffset[1];
break; //don't need to check anymore
}
}
}
}
short refIndex = (short)0; //check when these indexes change
short cinfoIndex = (short)0;
short utf8Index = (short)0;
short nameAndTypeIndex =(short)0;
short mfRefIndex = (short)0;
int resolveFlag = 0; //check when changes and when changes back (Per loop)
boolean isRef(short cl, short nat)
throws UnsupportedEncodingException, IOException
{ Vector cptemp1 = cptemp;
Vector frefs = new Vector();
Vector mrefs = new Vector();
Vector FRefs = new Vector();
Vector MRefs = new Vector();
mfRefIndex = (short)0; //in case changed somewhere before
for (int i=0; i<cptemp1.size(); i++)
{ Cp_info cpEntry = (Cp_info)cptemp1.get(i);
Short presentIndex = new Short((short)(i+1));
if (cpEntry.tag == (byte)0x9) //fref
{ frefs.add(cpEntry);
FRefs.add(presentIndex);
}
else if (cpEntry.tag == (byte)0xa) //mref
{ mrefs.add(cpEntry);
MRefs.add(presentIndex);
}
}
for (int k=0; k<frefs.size(); k++)
{ CONSTANT_Fieldref_info cpEntry =
(CONSTANT_Fieldref_info)frefs.get(k);
if ((cpEntry.class_index == cl) &
(cpEntry.name_and_type_index == nat))
{ mfRefIndex = ((Short)FRefs.get(k)).shortValue();
return true;
}
}
for (int j=0; j<mrefs.size(); j++)
{ CONSTANT_Methodref_info cpEntry =
(CONSTANT_Methodref_info)mrefs.get(j);
if ((cpEntry.class_index == cl) &
(cpEntry.name_and_type_index == nat))
{ mfRefIndex = ((Short)MRefs.get(j)).shortValue();
return true;
}
}
return false;
}
boolean isNAT(short nm, short des)
throws UnsupportedEncodingException, IOException
{ Vector cptemp1 = cptemp;
for (int i=0; i<cptemp1.size(); i++)
{ Cp_info cpEntry = (Cp_info)cptemp1.get(i);
short presentIndex = (short)(i+1);
if (cpEntry.tag == (byte)0xc) //NAT_info
{ CONSTANT_NameAndType_info natEntry =
(CONSTANT_NameAndType_info)cpEntry;
if ((natEntry.name_index == nm) &
(natEntry.descriptor_index == des))
{ nameAndTypeIndex = presentIndex;
//System.out.println("************FOUND A NAT MATCH");
return true;
}
}
}
return false;
}
void lookupUtf8(String utf8)
throws UnsupportedEncodingException, IOException
{ Vector cptemp1 = cptemp;
Vector utf8s = new Vector(); //vectors for holding cp_info itself
Vector Utf8s = new Vector(); //vectors for holding cp-indexes
//System.out.println(cptemp1.size()+" CP entries");
for (int i=0; i<cptemp1.size(); i++)
{ Cp_info cpEntry = (Cp_info)cptemp1.get(i);
Short presentIndex = new Short((short)(i+1));
// i.e. give cp-index, not vector index by i+1...
// ...because first entry in CP is cp[1] NOT cp[0]
switch (cpEntry.tag)
{
case (byte)0x1: //Utf8_info
utf8s.add(cpEntry);
//System.out.println(presentIndex+ " we have a utf8");
Utf8s.add(presentIndex); break;
default:
break;
}
}
short index = (short)-1;
for (int i=0; i<utf8s.size(); i++)
{ CONSTANT_Utf8_info cpEntry = (CONSTANT_Utf8_info)utf8s.get(i);
String compare = new String(cpEntry.bytes, "UTF-8");
//System.out.println(utf8 + " == " + compare+" ?");
if (utf8.equals(compare))
{ index = ((Short)Utf8s.get(i)).shortValue();
//System.out.println("Hello. we got UTF8 match. Index no. "+index);
break; // assume there is only one match or no match
}
}
if (index == (short)-1) // i.e. no utf8 matches found
utf8Index = 0; // in case this value has been changed
else utf8Index = index;
}
void lookupCinfo(String classname, Code_attribute ca, boolean b)
// just like lookupRef
throws UnsupportedEncodingException, IOException
{ Vector cptemp1 = cptemp;
Vector utf8s = new Vector(); //vectors for holding cp_info itself
Vector classes = new Vector();
Vector Utf8s = new Vector(); //vectors for holding cp-indexes
Vector Classes = new Vector();
//System.out.println(cptemp1.size()+" CP entries");
for (int i=0; i<cptemp1.size(); i++)
{ Cp_info cpEntry = (Cp_info)cptemp1.get(i);
Short presentIndex = new Short((short)(i+1));
// i.e. give cp-index, not vector index by i+1...
// ...because first entry in CP is cp[1] NOT cp[0]
switch (cpEntry.tag)
{
case (byte)0x1: //Utf8_info
utf8s.add(cpEntry);
//System.out.println(presentIndex+ " we have a utf8");
Utf8s.add(presentIndex);
break;
case (byte)0x7: //class_info
classes.add(cpEntry);
//System.out.println(presentIndex+ " we have a class");
Classes.add(presentIndex);
break;
default:
break;
}
}
short index = (short)-1;
for (int i=0; i<utf8s.size(); i++)
{ CONSTANT_Utf8_info cpEntry = (CONSTANT_Utf8_info)utf8s.get(i);
String compare = new String(cpEntry.bytes, "UTF-8");
//System.out.println(classname + " == " + compare+" ?");
if (classname.equals(compare))
{ index = ((Short)Utf8s.get(i)).shortValue();
//System.out.println("Hello. we got a match. Index no. "+index);
break; // assume there is only one match or no match
}
}
if (index == (short)-1) //i.e. no utf8 matches found
{ cinfoIndex = 0; //in case this value has been changed
if (b) addToResolveClass(classname, ca);
return;
}
else
{ for (int i=0; i<classes.size(); i++)
{ CONSTANT_Class_info cpEntry =
(CONSTANT_Class_info)classes.get(i);
if (cpEntry.name_index == index)
{ cinfoIndex = ((Short)Classes.get(i)).shortValue();
//System.out.println("Class_info match. index no. "+cinfoIndex);
break; //assume only one match for NAT or no match
}
}
}
}
void lookupRef(String name, Code_attribute ca)
//works for field_info as well as method_info (I hope)
throws UnsupportedEncodingException, IOException
{ Vector cptemp1 = cptemp;
Vector utf8s = new Vector(); //vectors for holding cp_info itself
Vector nats = new Vector();
Vector mrefs = new Vector();
Vector classes = new Vector();
Vector frefs = new Vector();
Vector Utf8s = new Vector(); //vectors for holding cp-indexes
Vector Nats = new Vector();
Vector Mrefs = new Vector();
Vector Classes = new Vector();
Vector Frefs = new Vector();
//System.out.println(cptemp1.size()+" CP entries");
for (int i=0; i<cptemp1.size(); i++)
{ Cp_info cpEntry = (Cp_info)cptemp1.get(i);
Short presentIndex = new Short((short)(i+1));
// i.e. give cp-index, not vector index by i+1...
// ...because first entry in CP is cp[1] NOT cp[0]
switch (cpEntry.tag)
{
case (byte)0x1: //Utf8_info
utf8s.add(cpEntry);
Utf8s.add(presentIndex);
break;
case (byte)0xc: //nat_info
nats.add(cpEntry);
Nats.add(presentIndex);
break;
case (byte)0xa: //mref_info
mrefs.add(cpEntry);
Mrefs.add(presentIndex);
break;
case (byte)0x7: //class_info
classes.add(cpEntry);
Classes.add(presentIndex);
break;
case (byte)0x9: //fieldref_info
frefs.add(cpEntry);
Frefs.add(presentIndex);
break;
default:
//System.out.println("some other type of Cp_info?");
break;
}
}
short index = (short)-1;
short natIndex = (short)-1;
short mrefidx = (short)-1;
for (int i=0; i<utf8s.size(); i++)
{ CONSTANT_Utf8_info cpEntry = (CONSTANT_Utf8_info)utf8s.get(i);
String compare = new String(cpEntry.bytes, "UTF-8");
//System.out.println(name + " == " + compare+" ?");
if (name.equals(compare))
{ index = ((Short)Utf8s.get(i)).shortValue();
//System.out.println("Hello. we got a match. Index no. "+index);
break; // assume there is only one match or no match
}
}
if (index == (short)-1) //i.e. no utf8 matches found
{ if (resolveFlag == 0)
{ addToResolveList(name, ca);
refIndex = (short)0; //incase it contains a value from previous call
//System.out.println("this method/field not found...so far");
return; //i.e. return from method if no utf8 match
}
else //i.e. part of resolveAll() so addToResolveList() already done
//System.out.println("ERROR! Method "+name+" was NEVER declared")
;
}
//ASSUMPTION: there are no fields (or other utf8s) by same name as method
//if there is a field then next stage would find a fieldref
//and say we can't cast to Methodref_info as a result
else
{
for (int i=0; i<nats.size(); i++)
{ CONSTANT_NameAndType_info cpEntry =
(CONSTANT_NameAndType_info)nats.get(i);
if (cpEntry.name_index == index)
{ natIndex = ((Short)Nats.get(i)).shortValue();
//System.out.println("NAT match. Natindex no. "+natIndex);
if (natIndex == initNAT)
continue; //continue with loop and look for next match
else break;
}
}
}
if (natIndex == (short)-1)
{
//System.out.println("name "+name+" not a method(or maybe 'main'");
return;
}
//ASSUMPTION: we are not going to have overloaded methods
//otherwise need to check that type descriptor matches too
//also assume there is NOT both methodref+fieldref for any string
else
{
for(int i=0; i<mrefs.size(); i++)
{ CONSTANT_Methodref_info cpEntry =
(CONSTANT_Methodref_info)mrefs.get(i);
if (cpEntry.name_and_type_index == natIndex)
{ mrefidx = ((Short)Mrefs.get(i)).shortValue();
//System.out.println("Methodref_info MATCH! no. "+mrefidx);
refIndex=mrefidx;
}
}
for(int i=0; i<frefs.size(); i++)
{ CONSTANT_Fieldref_info cpEntry =
(CONSTANT_Fieldref_info)frefs.get(i);
if (cpEntry.name_and_type_index == natIndex)
{ mrefidx = ((Short)Frefs.get(i)).shortValue();
//System.out.println("Fieldref_info MATCH! no. "+mrefidx);
refIndex=mrefidx;
}
}
}
if (mrefidx == (short)-1) //i.e. couldn't find the mref_idx
//System.out.println("something wrong? utf8, NAT but no methodref")
;
}
void printCP() //prints out contents of final CP entries
//makes use of lookup...() technology
throws UnsupportedEncodingException, IOException
{ Vector cptemp1 = cptemp;
Vector utf8s = new Vector(); //vectors for holding cp_info itself
Vector nats = new Vector();
Vector mrefs = new Vector();
Vector classes = new Vector();
Vector frefs = new Vector();
Vector Utf8s = new Vector(); //vectors for holding cp-indexes
Vector Nats = new Vector();
Vector Mrefs = new Vector();
Vector Classes = new Vector();
Vector Frefs = new Vector();
//System.out.println(cptemp1.size()+" CP entries");
for (int i=0; i<cptemp1.size(); i++)
{ Cp_info cpEntry = (Cp_info)cptemp1.get(i);
Short presentIndex = new Short((short)(i+1));
//i.e. give cp-index, not vector index by i+1...
//...because first entry in CP is cp[1] NOT cp[0]
switch (cpEntry.tag)
{
case (byte)0x1: //Utf8_info
utf8s.add(cpEntry);
CONSTANT_Utf8_info cpEntry1 = (CONSTANT_Utf8_info)cpEntry;
String utf8name = new String(cpEntry1.bytes, "UTF-8");
//System.out.println("cp["+presentIndex+ "]\tutf8:\t"+utf8name);
Utf8s.add(presentIndex);
break;
case (byte)0xc: //nat_info
nats.add(cpEntry);
CONSTANT_NameAndType_info cpEntry2 =
(CONSTANT_NameAndType_info)cpEntry;
short nmix = cpEntry2.name_index;
short tyix = cpEntry2.descriptor_index;
//System.out.println("cp["+presentIndex+ "]\tnat:\t"+
// nmix+","+tyix);
Nats.add(presentIndex);
break;
case (byte)0xa: //mref_info
mrefs.add(cpEntry);
CONSTANT_Methodref_info cpEntry3 =
(CONSTANT_Methodref_info)cpEntry;
short clix = cpEntry3.class_index;
short ntix = cpEntry3.name_and_type_index;
//System.out.println("cp["+presentIndex+ "]\tmref:\t"+clix+","+ntix);
Mrefs.add(presentIndex);
break;
case (byte)0x7: //class_info
classes.add(cpEntry);
CONSTANT_Class_info cpEntry4 = (CONSTANT_Class_info)cpEntry;
nmix = cpEntry4.name_index;
//System.out.println("cp["+presentIndex+ "]\tclass:\t"+nmix);
Classes.add(presentIndex);
break;
case (byte)0x9: //fieldref_info
frefs.add(cpEntry);
CONSTANT_Fieldref_info cpEntry5 =
(CONSTANT_Fieldref_info)cpEntry;
clix = cpEntry5.class_index;
ntix = cpEntry5.name_and_type_index;
//System.out.println("cp["+presentIndex+ "]\tfref:\t"+
// clix+","+ntix);
Frefs.add(presentIndex);
break;
default:
//System.out.println("some other type of Cp_info?");
break;
}
}
}
Vector toResolve = new Vector(); // hold names to be resolved
Vector mcounts = new Vector(); // which methods[i] it appears in
Vector pointers = new Vector(); // which bit of code to be changed
void addToResolveList(String name, Code_attribute ca)
{
toResolve.add(name); //method name to be resolved
Short methodIndex = new Short(methods_count);
mcounts.add(methodIndex); //which method the code appears in
Integer pointer = new Integer(ca.code.length); //length is where you
//got upto before when the cp index was needed and NOT resolved
pointers.add(pointer);//pointer to which code to be amended
//Vector of strings to resolve, with index of where to update in code.
}
Vector toResolveC = new Vector(); // hold names to be resolved
Vector mcountsC = new Vector(); // which methods[i] it appears in
Vector pointersC = new Vector(); // which bit of code to be changed
void addToResolveClass(String name, Code_attribute ca) //for resolving class_infos
{
toResolveC.add(name); //method name to be resolved
Short methodIndex = new Short(methods_count);
mcountsC.add(methodIndex); //which method the code appears in
Integer pointer = new Integer(ca.code.length); //length is where you
//got upto before when the cp index was needed and NOT resolved
pointersC.add(pointer);//pointer to which code to be amended
//Vector of strings to resolve, with index of where to update in code.
}
void resolveAll() throws IOException, UnsupportedEncodingException
{
//System.out.println("*****NUMBER OF REFS TO RESOLVE IS: "+toResolve.size());
for (int i=0; i<toResolve.size(); i++)
{ resolveFlag = 1; //to say that this is resolveAll()
Code_attribute ca = new Code_attribute();
// made purely for passing on to satisfy parameter requirements
// of lookupMref
lookupRef((String)toResolve.get(i), ca);
byte[] newIndex = ByteArray.shortToByteArray(refIndex);
int pointer = ((Integer)pointers.get(i)).intValue();
short methodIndex = ((Short)mcounts.get(i)).shortValue();
(methods[methodIndex].attributes[0]).info[pointer+8+1]=newIndex[0];
(methods[methodIndex].attributes[0]).info[pointer+8+2]=newIndex[1];
}
//System.out.println("RESOLVE-REFS ALL DONE");
//System.out.println("*****NUMBER OF CINFOS TO RESOLVE IS: "+toResolveC.size());
for (int i=0; i<toResolveC.size(); i++)
{ Code_attribute ca = new Code_attribute();
lookupCinfo((String)toResolveC.get(i), ca, false);
byte[] newIndex = ByteArray.shortToByteArray(cinfoIndex);
int pointer = ((Integer)pointersC.get(i)).intValue();
short methodIndex = ((Short)mcountsC.get(i)).shortValue();
(methods[methodIndex].attributes[0]).info[pointer+8+1]=newIndex[0];
(methods[methodIndex].attributes[0]).info[pointer+8+2]=newIndex[1];
}
//System.out.println("RESOLVE-CLASSES ALL DONE");
resolveLabels();
}
//NEED RESOLVE TO DEAL WITH CLASSINFO too:
void makeCP() throws UnsupportedEncodingException
{
cptemp.trimToSize(); //no need for this? capacity vs. size
constant_pool_count = (short)(cptemp.size()+1);
//System.out.println("constant_pool_count = " + constant_pool_count);
constant_pool = new Cp_info[constant_pool_count-1];
for (int i=0; i<cptemp.size(); i++)
{ constant_pool[i] = (Cp_info)(cptemp.get(i));
// System.out.println("\n\n" + i);
// constant_pool[i].printBytes(constant_pool[i].dumpBytes());
}
}
byte[] dumpBytes()
{ byte[][] Bytes = new byte[13][0];
Bytes[0] = ByteArray.intToByteArray(MAGIC);
Bytes[1] = ByteArray.shortToByteArray(minor_version);
Bytes[2] = ByteArray.shortToByteArray(major_version);
Bytes[3] = ByteArray.shortToByteArray(constant_pool_count);
Bytes[4] = ByteArray.cpToByteArray(constant_pool);
Bytes[5] = ByteArray.shortToByteArray(access_flags);
Bytes[6] = ByteArray.shortToByteArray(this_class);
Bytes[7] = ByteArray.shortToByteArray(super_class);
Bytes[8] = ByteArray.shortToByteArray(interfaces_count);
// ignore interfaces[] since never likely to need it
Bytes[9] = ByteArray.shortToByteArray(fields_count);
Bytes[10] = ByteArray.shortToByteArray(methods_count);
Bytes[11] = ByteArray.miToByteArray(methods);
Bytes[12] = ByteArray.shortToByteArray(attributes_count);
//Bytes[13] = attributes[0].dumpBytes();
// Bytes[16] = ByteArray.byteToByteArray((byte)0);
// Is zero at end of class file? (eof marker?)
ClassBytes = ByteArray.flatBytes(Bytes);
return ClassBytes;
}
//writes byte array to a file
void bytesToFile(byte[] Bytes)
throws IOException, FileNotFoundException
{
//File f1 = new File("D:/jlisp/MyCode/"+thisString+".class");
File f1 = new File("./"+thisString+".class");
DataOutputStream outStream =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(f1)));
for (int i=0; i<Bytes.length; i++)
outStream.writeByte(Bytes[i]);
outStream.close();
}
Object loadCF()
throws IOException, ClassNotFoundException,
InstantiationException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException
{
// This loads a class using the current CLASSPATH...
JlispClassLoader loader = new JlispClassLoader();
Object r = loader.loadMyInstance(thisString);
//System.out.println("Object = " + r + " of type " + r.getClass());
return r;
}
Object instanceFromBytes()
throws IOException, ClassNotFoundException,
InstantiationException, IllegalAccessException,
NoSuchMethodException, InvocationTargetException
{
// Load a class from an array of bytes and create an instance of it.
// byte [] bytes = dumpBytes(); //no need to...ClassBytes
JlispClassLoader loader = new JlispClassLoader();
Object r = loader.loadMyInstance(thisString, ClassBytes);
//System.out.println("Object = " + r + " of type " + r.getClass());
return r;
}
}
// end of ClassDescription.java