package js.tools;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.TreeSet;
/**
* A comparable ArrayList.
*/
class Packing implements Comparable<Packing>
{
Size array[];
int thisSize;
// Construct a fully functioning object
Packing ()
{
array = new Size[CodePacker.list.size()];
thisSize = 0;
}
// Add an element if there is room.
boolean add (int i)
{
Size size = CodePacker.list.get(i);
if (size.size + thisSize <= CodePacker.maxSize)
{
array[i] = size;
thisSize += size.size;
return true;
}
return false;
}
void remove (int i)
{
if (array[i] != null)
{
thisSize -= array[i].size;
array[i] = null;
}
}
int getSize ()
{
return thisSize;
}
/**
* Pick a cross-over point within the index range. length/2 points before it
* come from one array, the other come from the other array until the
* capacity gets busted.
*/
Packing breed (Packing other)
{
int crossOver = (int) (Math.random() * array.length);
Packing offspring = new Packing();
for (int i = 0; i < array.length / 2; i++)
{
if (array[(i + crossOver) % array.length] != null)
offspring.add((i + crossOver) % array.length);
if (array[(i + array.length / 2 + crossOver) % array.length] != null)
offspring.add((i + array.length / 2 + crossOver) % array.length);
}
offspring.mutate();
return offspring;
}
void mutate ()
{
for (int i = 0; i < array.length; i++)
{
if (Math.random() > 0.5)
{
if (array[i] == null)
add(i);
else
remove(i);
}
}
}
public int compareTo (Packing other)
{
return thisSize - other.thisSize;
}
}
class Size
{
int size;
String file;
Size (int size, String file)
{
this.size = size;
this.file = file;
}
}
public class CodePacker
{
static ArrayList<Size> list;
static int maxSize;
/**
* Shuffle the passed list.
*/
static void shuffle ()
{
for (int i = 0; i < list.size() - 1; i++)
{
int selIndex = (int) (Math.random() * (list.size() - i) + i);
Size selected = list.get(selIndex);
list.set(selIndex, list.get(i));
list.set(i, selected);
}
}
/**
* Randomly select a set of n elements from the passed list until the total
* size of those elements would exceed the specified maximum size.
* <P>
* This is like shuffling the passed list and then selecting the first n
* elements, except we stop shuffling once the exit criteria has been met.
*/
static Packing select (int indices[])
{
Packing selection = new Packing();
for (int i = 0; i < indices.length - 1; i++)
{
int selIndex = (int) (Math.random() * (indices.length - i) + i);
int at = indices[selIndex];
indices[selIndex] = indices[i];
indices[i] = at;
selection.add(i);
}
return selection;
}
static Packing pack ()
{
// Create an array of indices into the passed list:
int indices[] = new int[list.size()];
for (int i = 0; i < indices.length; i++)
{
indices[i] = i;
}
// Generate an initial random set of packings of size indices.length
TreeSet<Packing> populations = new TreeSet<Packing>();
for (int i = 0; i < indices.length; i++)
{
Packing packing = select(indices);
// If we've already got a perfect packing, just return it.
if (packing.thisSize == maxSize)
{
return packing;
}
populations.add(packing);
}
// Breed for a while.
for (int i = 0; i < indices.length * 2; i++)
{
// Select two elements at random to breed
Packing array[] = populations.toArray(new Packing[populations.size()]);
Packing offspring = array[i % array.length].breed(array[(int) (Math
.random() * array.length)]);
if (offspring.thisSize == maxSize)
return offspring;
// Add the new offspring and remove the least fit.
if (populations.add(offspring))
populations.remove(populations.first());
}
return populations.last();
}
public static void main (String[] args) throws Exception
{
int extraStart = 0;
String ldsFile = args[0];
String mapFile = args[1];
String outputFile = args[2];
StringBuffer prologue = new StringBuffer();
StringBuffer epilogue = new StringBuffer();
StringBuffer current = prologue;
list = new ArrayList<Size>();
// Locate 'extra1'
BufferedReader br = new BufferedReader(new FileReader(ldsFile));
String s;
while ((s = br.readLine()) != null)
{
current.append(s);
current.append("\n");
StringTokenizer st = new StringTokenizer(s);
if (st.hasMoreTokens())
{
String token = st.nextToken();
if (token.equals("extra1"))
{
st.nextToken(); // :
st.nextToken(); // o
st.nextToken(); // =
token = st.nextToken();
extraStart = Integer.decode(token).intValue();
st.nextToken(); // ,
st.nextToken(); // l
st.nextToken(); // =
token = st.nextToken();
maxSize = Integer.decode(token).intValue();
}
}
if (s.indexOf("__extra_start") != -1)
current = epilogue;
}
br.close();
// Read in the size of all of the .o's.
br = new BufferedReader(new FileReader(mapFile));
while ((s = br.readLine()) != null)
{
StringTokenizer st = new StringTokenizer(s);
if (st.hasMoreTokens())
{
String token = st.nextToken();
if (token.equals(".text"))
{
// Discard the next token
st.nextToken();
// Next token is the size in hex;
int size = Integer.decode(st.nextToken()).intValue();
// Next token is the name of the object file
String file = st.nextToken();
if (!file.equals("main.o") && file.indexOf("init.o") == -1)
{
// Is this a file in a library?
int lparenI = file.indexOf("(");
// GNU LD doesn't make life easy...
if (lparenI != -1)
{
int rparenI = file.indexOf(")");
file = "*" + file.substring(lparenI + 1, rparenI);
}
list.add(new Size(size, file));
}
}
}
}
Packing packing = pack();
System.out.println("Segment size=" + maxSize + ", packing size="
+ packing.thisSize);
PrintWriter pw = new PrintWriter(new FileWriter(outputFile));
pw.print(prologue);
for (int i = 0; i < packing.array.length; i++)
{
if (packing.array[i] != null)
{
pw.println(packing.array[i].file + "(.text)");
}
}
pw.print(epilogue);
pw.close();
}
}