/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2005-2008, Martin Schoeberl (martin@jopdesign.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Created on 04.06.2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package com.jopdesign.build;
import java.util.*;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
/**
*
* Build virtual method tables and the one and only interface table.
*
* @author martin
*
*/
public class BuildVT extends JOPizerVisitor {
Map mapClVT = new HashMap();
Map mapClFT = new HashMap();
public BuildVT(OldAppInfo jz) {
super(jz);
}
public void visitJavaClass(JavaClass clazz) {
super.visitJavaClass(clazz);
// don't get confused in the build process
setCli(null);
// TODO: if (!array class) ...
buildVT(clazz);
if (clazz.isInterface()) {
buildIT(clazz);
}
}
/**
* Called recursive to build the VTs top down.
*
* @param clazz
*/
private void buildVT(JavaClass clazz) {
int i, j;
// System.err.println("invoke buildVT on class: "+clazz);
JopClassInfo cli;
cli = (JopClassInfo) ai.cliMap.get(clazz.getClassName());
// System.err.println("build VT on class: "+cli.clazz);
/*
* TODO: we have TWO mappings of clazzes: in JOPWriter AND in ClassInfo
* However, they are not consistent!
* The following results in a null pointer for java.lang.Object:
cli = jz.getClassInfo(clazz);
System.err.println("build VT on class: "+cli.clazz);
*/
JopClassInfo.ClVT supVt = null;
JopClassInfo.ClFT supFt = null;
if (clazz.getClassName().equals(clazz.getSuperclassName())) {
; // now we'r Object
} else {
OldClassInfo clisup = (OldClassInfo) ai.cliMap.get(clazz.getSuperclassName());
// JavaClass superClazz = clazz.getSuperClass();
// System.err.println("super: "+superClazz);
JavaClass superClazz = clisup.clazz;
String superName = superClazz.getClassName();
// System.err.println("super name: "+superName);
if (mapClVT.get(superName)==null) {
// System.err.println("rec. invoke buildVT with: "+superClazz);
buildVT(superClazz); // first build super VT
}
supVt = (JopClassInfo.ClVT) mapClVT.get(superName);
supFt = (JopClassInfo.ClFT) mapClFT.get(superName);
}
// System.err.println("build VT on: "+clazz.getClassName());
String clazzName = clazz.getClassName();
if (mapClVT.get(clazzName)!=null) {
return; // allready done!
}
// this also tries to load from application CLASSPATH
// int intfCount = clazz.getInterfaces().length;
// System.err.println(cli);
JopClassInfo.ClVT clvt = cli.getClVT();
JopClassInfo.ClFT clft = cli.getClFT();
mapClVT.put(clazzName, clvt);
mapClFT.put(clazzName, clft);
Method m[] = clazz.getMethods();
int methodCount = m.length;
int maxLen = methodCount;
if (supVt!=null) maxLen += supVt.len;
try {
for (JavaClass cl : clazz.getInterfaces()) {
maxLen += cl.getMethods().length;
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new Error();
}
clvt.len = 0;
clvt.key = new String[maxLen];
// clvt.ptr = new int[maxLen];
clvt.mi = new JopMethodInfo[maxLen];
Field f[] = clazz.getFields();
maxLen = f.length;
// if (supFt!=null) maxLen += supFt.len;
clft.len = 0;
clft.key = new String[maxLen];
clft.idx = new int[maxLen];
clft.size = new int[maxLen];
clft.isStatic = new boolean[maxLen];
clft.isReference = new boolean[maxLen];
// System.out.println("// VT: "+clazzName);
if (supVt!=null) {
for (i=0; i<supVt.len; ++i) {
clvt.key[i] = supVt.key[i];
// System.out.println("//super: "+clvt.key[i]);
clvt.mi[i] = supVt.mi[i];
}
clvt.len = supVt.len;
}
/*
if (supFt!=null) {
for (i=0; i<supFt.len; ++i) {
// copy only the non static fields
if (!supFt.isStatic[i]) {
clft.key[clft.len] = supFt.key[i];
clft.idx[clft.len] = supFt.idx[i];
clft.size[clft.len] = supFt.size[i];
clft.isStatic[clft.len] = supFt.isStatic[i];
clft.isReference[clft.len] = supFt.isReference[i];
++clft.len;
}
}
}
*/
for (i = 0; i < methodCount; i++) {
Method meth = m[i];
String methodId = meth.getName()+meth.getSignature();
JopMethodInfo mi = (JopMethodInfo) cli.getMethodInfo(methodId);
for (j=0; j<clvt.len; ++j) {
if (clvt.key[j].equals(methodId)) { // override method
//System.out.println("override "+methodId);
clvt.mi[j] = mi;
break;
}
}
if (j==clvt.len) { // new method
clvt.key[clvt.len] = methodId;
//System.out.println("new "+methodId);
clvt.mi[clvt.len] = mi;
++clvt.len;
}
}
// add interface methods that are not actually implemented here
try {
for (i = 0; i < clazz.getInterfaces().length; i++) {
OldClassInfo icli = ai.cliMap.get(clazz.getInterfaces()[i].getClassName());
for (String methodId : icli.methods.keySet()) {
for (j=0; j<clvt.len; ++j) {
if (clvt.key[j].equals(methodId)) { // ok, we have the method
break;
}
}
if (j==clvt.len) { // method not found
clvt.key[clvt.len] = methodId;
clvt.mi[clvt.len] = (JopMethodInfo)icli.methods.get(methodId);
++clvt.len;
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new Error();
}
//System.out.println("The VT of "+clazzName);
//for (i=0; i<clvt.len; i++) {
// System.out.println("//\t"+clvt.meth[i].cli.clazz.getClassName()+"."+clvt.key[i]);
//}
// this is strange!!!
// BTW we copied only the non static fields....
int nextFieldIndex = 0;
int nextStaticIndex = 0;
/*
for (j=0; j<clft.len; ++j) {
int size = clft.size[j];
if (clft.isStatic[j]) {
nextStaticIndex += size;
} else {
nextFieldIndex += size;
}
}
*/
if (supFt!=null) {
nextFieldIndex = supFt.instSize;
for (i=0; i<supFt.len; ++i) {
if (supFt.isStatic[i]) {
if (supFt.idx[i]>=nextStaticIndex) {
nextStaticIndex = supFt.idx[i]+1;
}
/*
} else {
if (supFt.idx[i]>=nextFieldIndex) {
nextFieldIndex = supFt.idx[i]+1;
}
*/
}
}
}
for (i=0; i<f.length; ++i) {
Field field = f[i];
int size = field.getType().getSize();
String fieldId = field.getName()+field.getSignature();
clft.key[clft.len] = fieldId;
clft.size[clft.len] = size;
clft.isReference[clft.len] = field.getType() instanceof ReferenceType;
if (field.isStatic()) {
clft.idx[clft.len] = nextStaticIndex;
clft.isStatic[clft.len] = true;
nextStaticIndex += size;
} else {
clft.idx[clft.len] = nextFieldIndex;
clft.isStatic[clft.len] = false;
nextFieldIndex += size;
}
clft.len++;
}
// This is redundant!
clft.instSize = nextFieldIndex;
cli.setInstanceSize(nextFieldIndex);
}
private void buildIT(JavaClass clazz) {
int i, j;
OldClassInfo cli = (OldClassInfo) ai.cliMap.get(clazz.getClassName());
Method m[] = clazz.getMethods();
int methodCount = m.length;
//
// build global interface table
//
for (i = 0; i < methodCount; i++) {
Method meth = m[i];
String methodId = meth.getName()+meth.getSignature();
JopMethodInfo mi = (JopMethodInfo) cli.getMethodInfo(methodId);
JopClassInfo.IT it = JopClassInfo.getITObject();
it.nr = JopClassInfo.listIT.size();
it.key = methodId;
// System.out.println("Add to IT: "+it.nr+" "+it.key);
it.meth = mi;
JopClassInfo.listIT.add(it);
}
}
}