/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2009, Benedikt Huber (benedikt.huber@gmail.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/>.
*/
package com.jopdesign.wcet.jop;
import com.jopdesign.common.ClassInfo;
import com.jopdesign.common.type.MemberID;
import com.jopdesign.wcet.WCETTool;
import org.apache.log4j.Logger;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
/**
* Build map for data addresses, provided by the linker
*
* @author Benedikt Huber (benedikt.huber@gmail.com)
*
* FIXME: [processor-model] Abstract LinkerInfo (even if jamuth support will never be accomplished)
*/
public class LinkerInfo {
public class LinkInfo {
private ClassInfo klass;
private int clinfoAddress;
private int constsAddress;
private int instSize;
private int superAddress;
private Map <String,Integer> staticAddresses = new HashMap<String,Integer>();
private Map <String,Integer> fieldOffsets = new HashMap<String,Integer>(); // ID (name+signature) to field index */
private Map <String,Integer> codeAddresses = new HashMap<String,Integer>();
private Map <String,Integer> mtabAddresses = new HashMap<String,Integer>();
private Map <Integer,Integer> constMap = new TreeMap<Integer,Integer>();
private Map<String, Integer> superClassFields = null; // loaded on demand
public LinkInfo(ClassInfo ci, int mtabAddress, int constsAddress) {
this.klass = ci;
this.clinfoAddress = mtabAddress - 5;
this.constsAddress = constsAddress;
this.superAddress = -1;
this.instSize = -1;
}
public ClassInfo getTargetClass() {
return klass;
}
public int getClassInfoAddress() {
return clinfoAddress;
}
public int getMTabAddress() {
return clinfoAddress + 5;
}
public int getMTabLength() {
return constsAddress - getMTabAddress();
}
public int getConstTableAddress() {
return constsAddress;
}
public int getSuperAddress() {
return superAddress;
}
private <K,V> void addAddress(String ctx, Map<K,V> amap, K key, V value) {
if(amap.containsKey(key)) {
throw new AssertionError("LinkerInfo.setAddress"+ctx+": Double entry for "+klass+"."+key);
}
amap.put(key, value);
}
private void setStaticFieldAddress(String name, int address) {
addAddress("StaticAddresses",staticAddresses,name,address);
}
private void setCodeAddress(String name, int address) {
addAddress("CodeAddresses",codeAddresses,name,address);
}
public int getInstanceSize() {
return this.instSize;
}
public int getStaticFieldAddress(String name) {
return staticAddresses.get(name);
}
public Integer getCodeAddress(String name) {
return codeAddresses.get(name);
}
public Integer getMTabAddress(String name) {
return mtabAddresses.get(name);
}
@Override
public String toString() {
return "LinkInfo "+this.klass.getClassName()+" "+clinfoAddress;
}
public void dump(PrintStream out) {
StringBuilder sb = new StringBuilder();
dump(sb);
out.println(sb);
}
public void dump(StringBuilder sb) {
sb.append("LinkInfo: "+this.klass.getClassName()+"\n");
sb.append(" instSize: "+this.instSize+"\n");
sb.append(" classInfo @ "+this.clinfoAddress+"\n");
sb.append(" mtab @ "+this.getMTabAddress()+"\n");
sb.append(" cpool @ "+this.constsAddress+"\n");
sb.append(" Static Addresses"+"\n");
for(Entry<String, Integer> entry : staticAddresses.entrySet()) {
sb.append(" " + entry.getKey() + " ==> " + entry.getValue()+"\n");
}
sb.append(" Code Addresses"+"\n");
for(Entry<String, Integer> entry : codeAddresses.entrySet()) {
sb.append(" " + entry.getKey() + " ==> " + entry.getValue()+"\n");
}
sb.append(" MTab Addresses"+"\n");
for(Entry<String, Integer> entry : mtabAddresses.entrySet()) {
sb.append(" " + entry.getKey()+" ==> " + entry.getValue()+"\n");
}
}
public Integer getConstAddress(int constIndex) {
if(! constMap.containsKey(constIndex)) return null;
return(constsAddress + constMap.get(constIndex) + 1);
}
public int getFieldOffset(String fieldName) {
loadSuperClassFields();
if(! fieldOffsets.containsKey(fieldName)) {
Logger.getLogger(LinkerInfo.class).error("No offset field for '"+fieldName+"' in "+klass+" only "+fieldOffsets);
return 0;
}
return(fieldOffsets.get(fieldName));
}
private Map<String, Integer> getFieldOffsets() {
loadSuperClassFields();
return fieldOffsets;
}
private void loadSuperClassFields() {
if(this.superClassFields != null) return;
if(this.klass.getSuperClassInfo() == null) return;
LinkInfo superLinkInfo;
try {
superLinkInfo = getOrCreateLinkInfo(klass.getSuperClassName());
} catch (ClassNotFoundException ignored) {
throw new AssertionError("Superclass not found: "+klass.getSuperClassName());
}
superClassFields = superLinkInfo.getFieldOffsets();
this.fieldOffsets.putAll(superClassFields);
}
public void parseInfo(String[] tks) {
String key = tks[0];
if(key.equals("-constmap")) {
int keyIx = Integer.parseInt(tks[1]);
int valIx = Integer.parseInt(tks[2]);
constMap.put(keyIx,valIx);
} else if(key.equals("-super")) {
this.superAddress = Integer.parseInt(tks[1]);
} else if(key.equals("-instSize")) {
this.instSize = Integer.parseInt(tks[1]);
} else if(key.equals("-field")) {
addAddress("FieldOffsets", fieldOffsets, tks[1], Integer.parseInt(tks[2]));
} else if (key.equals("-mtab")) {
MemberID nameParts = MemberID.parse(tks[1], true);
int valIx = Integer.parseInt(tks[2]);
addAddress("MTabAddresses",mtabAddresses,nameParts.getMethodSignature(), valIx);
} else {
throw new AssertionError("Bad format for class info (Unknown key: '" + key + "')" + Arrays.toString(tks));
}
}
}
private WCETTool project;
private Map<String, LinkInfo> classLinkInfo;
public Map<String, LinkInfo> getClassLinkInfo() {
return classLinkInfo;
}
public LinkerInfo(WCETTool p) {
this.project = p;
}
/** Load the linker info.
* Currently, we support the following entries in the Link file:
* <ul><li/>{@code static} fully-qualified-static-field-name address
* <li/>{@code bytecode} fully-qualified-method-name bytecode-start
* <li/>{@code class} class-name mtab-start cpool-start <br/>
* with subinfo
* <ul><li/> {@code -super} super-class-address
* <li/> {@code -mtab} method-name mtab-address
* <li/> {@code -constmap} constant-classfile-index constant-actual-index
* <li/> {@code -field} field-name field-offset
* </ul>
* </ul>
* @throws IOException
* @throws ClassNotFoundException
*/
public void loadLinkInfo() throws IOException, ClassNotFoundException {
//File jopFile = project.getProjectConfig().getBinaryFile());
// for(LinkInfo li : classLinkInfo.values()) {
// System.out.println(" "+li);
// }
classLinkInfo = new HashMap<String, LinkInfo>();
BufferedReader br = new BufferedReader(new FileReader(project.getProjectConfig().getLinkInfoFile()));
String l = br.readLine();
try {
while(l != null) {
LinkInfo linkInfo;
String[] tks = l.split("\\s+");
if(tks[0].equals("static") || tks[0].equals("bytecode")) {
MemberID nameParts = MemberID.parse(tks[1],true);
linkInfo = getOrCreateLinkInfo(nameParts.getClassName());
String objectName = nameParts.getMethodSignature();
int address = Integer.parseInt(tks[2]);
if(tks[0].equals("bytecode")) {
linkInfo.setCodeAddress(objectName, address);
} else {
linkInfo.setStaticFieldAddress(objectName, address);
}
} else if(tks[0].equals("class")) {
String classname = tks[1];
linkInfo = getOrCreateLinkInfo(classname);
linkInfo.clinfoAddress = Integer.parseInt(tks[2]) - 5;
linkInfo.constsAddress = Integer.parseInt(tks[3]);
} else {
throw new IOException("Bad format in link info file: "+l);
}
while((l=br.readLine()) != null) {
l = l.trim();
if(! l.startsWith("-")) break;
linkInfo.parseInfo(l.split("\\s"));
}
}
} finally {
br.close();
}
}
private LinkInfo getOrCreateLinkInfo(String classname) throws ClassNotFoundException {
ClassInfo klass = project.getAppInfo().getClassInfo(classname);
if(klass == null) throw new ClassNotFoundException(classname);
LinkInfo linkInfo = classLinkInfo.get(classname);
if(linkInfo == null) {
linkInfo = new LinkInfo(klass, 0, 0);
classLinkInfo.put(classname,linkInfo);
}
return linkInfo;
}
public LinkInfo getLinkInfo(ClassInfo cli) {
return classLinkInfo.get(cli.getClassName());
}
public Integer getStaticFieldAddress(String className, String fieldName) {
LinkInfo li;
try {
li = this.getOrCreateLinkInfo(className);
} catch (ClassNotFoundException ignored) {
return null;
}
return li.getStaticFieldAddress(fieldName);
}
/**
* Compute the (physical) index of a given field (using linker infos)
* @param klassName
* @param fieldName
* @return
*/
public int getFieldIndex(String klassName, String fieldName)
{
return classLinkInfo.get(klassName).getFieldOffset(fieldName);
}
public void dump(PrintStream out) {
for(Entry<String, LinkInfo> linkInfo : project.getLinkerInfo().getClassLinkInfo().entrySet()) {
linkInfo.getValue().dump(System.out);
}
}
}