package js.tinyvm; import java.io.IOException; import java.util.logging.Logger; import js.tinyvm.io.IByteWriter; /** * This class provides a represntation of an interface map. * The map is used at run time to determine if a class implements a particular * interface. The map is stored per interface and consists of a bitmap with 1 * bits for each class that implements the interface. The linker sorts the * classes to try and place classes that implement the same interfaces close * to each other. The map then takes advantage of this by using a sparse * implementation with a simple base and length positioning the actual variable * sized bitmap over the part of the class space that contains the required * classes. * @author andy */ public class InterfaceMap extends WritableDataWithOffset { private ClassRecord interfaceRecord; private Binary iBinary; private int firstClass; private int lastClass; private int size; public InterfaceMap(Binary iBinary, ClassRecord crec) throws TinyVMException { if (!crec.isInterface()) throw new TinyVMException("Attempt to create an interface map for a non interface class " + crec.iName); this.iBinary = iBinary; interfaceRecord = crec; findBounds(); } /** * Search the list of implemnting classes to determine that upper and lower * bounds for the map. */ private void findBounds() { // Search the list of implemnting classes to determine that upper and lower // bounds for the map lastClass = -1; firstClass = TinyVMConstants.MAX_CLASSES + 1; for(ClassRecord cr : interfaceRecord.iImplementedBy) { int index = iBinary.getClassIndex(cr); if (index > lastClass) lastClass = index; if (index < firstClass) firstClass = index; } if (lastClass < 0) size = 0; else size = lastClass - firstClass + 1; //System.out.println("Interface map for " + interfaceRecord.iName + " first " + firstClass + " last " + lastClass + " size " + size); } /** * Return the index of the first class implementing this interface. * @return index of the first class entry */ public int getFirst() { return firstClass; } /** * Return the number of "live" bits in the map. Any class index that is * < firstClass or >= firstClass + size is not in the map. * @return number of live bits */ public int getSize() { return size; } /** * return the number of bytes that make up this interface map. * @return size in bytes */ public int getLength () { return (size + 7)/8; } /** * Create the inetrface map, with one bit for each class that implements * this interface. * * @return array of bytes containing the map * @throws TinyVMException */ private byte[] createMap() throws TinyVMException { byte [] map = new byte[getLength()]; for(ClassRecord cr : interfaceRecord.iImplementedBy) { int index = iBinary.getClassIndex(cr) - firstClass; if (index >= size) throw new TinyVMException("Class index for " + cr.iName + " exceeds map size " + size + " for interface " + interfaceRecord.iName); map[index/8] |= 1 << (index % 8); } return map; } /** * Write the map to the executable file. * @param aOut access to the file writer * @throws TinyVMException */ public void dump (IByteWriter aOut) throws TinyVMException { byte [] map = createMap(); try { for(byte b : map) aOut.writeU1(b); } catch (IOException e) { throw new TinyVMException(e.getMessage(), e); } } private static final Logger _logger = Logger.getLogger("TinyVM"); }