1 cananian 1.1.2.1 // PackedClassFieldMap.java, created Wed Jul 11 20:26:56 2001 by cananian 2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Backend.Analysis; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.Backend.Maps.FieldMap; 7 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 8 cananian 1.1.2.1 import harpoon.ClassFile.HField; 9 cananian 1.1.2.1 import harpoon.Util.Util; 10 cananian 1.1.2.1 11 cananian 1.1.2.1 import java.util.ArrayList; 12 cananian 1.1.2.1 import java.util.Arrays; 13 cananian 1.1.2.1 import java.util.Collections; 14 cananian 1.1.2.1 import java.util.Comparator; 15 cananian 1.1.2.1 import java.util.HashMap; 16 cananian 1.1.2.1 import java.util.Iterator; 17 cananian 1.1.2.1 import java.util.LinkedList; 18 cananian 1.1.2.1 import java.util.List; 19 cananian 1.1.2.1 import java.util.ListIterator; 20 cananian 1.1.2.1 import java.util.Map; 21 cananian 1.1.2.1 /** 22 cananian 1.1.2.1 * <code>PackedClassFieldMap</code> is a <code>FieldMap</code> for 23 cananian 1.1.2.1 * non-static fields of a class which attempts to maximally fill holes 24 cananian 1.1.2.1 * in the data structure (even if this means commingling a subclass' 25 cananian 1.1.2.1 * fields with those of its superclass) in order to minimize the 26 cananian 1.1.2.1 * space required by objects. 27 cananian 1.1.2.1 * 28 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 29 cananian 1.4 * @version $Id: PackedClassFieldMap.java,v 1.4 2002/04/10 03:02:22 cananian Exp $ 30 cananian 1.1.2.1 */ 31 cananian 1.1.2.1 public abstract class PackedClassFieldMap extends FieldMap { 32 cananian 1.1.2.1 /** Creates a <code>PackedClassFieldMap</code>. */ 33 cananian 1.1.2.1 public PackedClassFieldMap() { /* no special initialization */ } 34 cananian 1.1.2.1 35 cananian 1.1.2.1 /** Return an offset to the given field. */ 36 cananian 1.1.2.1 public int fieldOffset(HField hf) { 37 cananian 1.3.2.1 assert !hf.isStatic(); 38 cananian 1.1.2.1 if (!fieldcache.containsKey(hf)) do_one(hf.getDeclaringClass()); 39 cananian 1.3.2.1 assert fieldcache.containsKey(hf); 40 cananian 1.3.2.2 return fieldcache.get(hf).intValue(); 41 cananian 1.1.2.1 } 42 cananian 1.1.2.1 /** Return an unmodifiable List over all appropriate fields in the given 43 cananian 1.1.2.1 * class, in order from smallest to largest offset. */ 44 cananian 1.3.2.2 public List<HField> fieldList(HClass hc) { 45 cananian 1.1.2.1 // get list of all fields in this class and its parents. 46 cananian 1.3.2.2 List<HField> l = new ArrayList<HField>(); 47 cananian 1.1.2.1 for (HClass p = hc; p!=null; p=p.getSuperclass()) 48 cananian 1.1.2.1 l.addAll(Arrays.asList(p.getDeclaredFields())); 49 cananian 1.1.2.1 // weed out static fields 50 cananian 1.3.2.2 for (Iterator<HField> it=l.iterator(); it.hasNext(); ) 51 cananian 1.3.2.2 if (it.next().isStatic()) 52 cananian 1.1.2.1 it.remove(); 53 cananian 1.1.2.1 // now sort by fieldOffset. 54 cananian 1.3.2.2 Collections.sort(l, new Comparator<HField>() { 55 cananian 1.3.2.2 public int compare(HField hf1, HField hf2) { 56 cananian 1.1.2.1 return fieldOffset(hf1) - fieldOffset(hf2); 57 cananian 1.1.2.1 } 58 cananian 1.1.2.1 }); 59 cananian 1.1.2.2 // quick verification of well-formedness 60 cananian 1.1.2.2 // (offsets must be strictly increasing) 61 cananian 1.1.2.2 int last=-1; 62 cananian 1.3.2.2 for (Iterator<HField> it=l.iterator(); it.hasNext(); ) { 63 cananian 1.3.2.2 int off=fieldOffset(it.next()); 64 cananian 1.3.2.1 assert last<off : "Ill-formed field list"; 65 cananian 1.1.2.2 last = off; 66 cananian 1.1.2.2 } 67 cananian 1.1.2.1 // done! 68 cananian 1.1.2.1 return l; 69 cananian 1.1.2.1 } 70 cananian 1.1.2.1 71 cananian 1.1.2.1 /** this method assigns "good" offsets to all the fields in class hc, 72 cananian 1.1.2.1 * using the assignments in hc's superclass and the list of free space 73 cananian 1.1.2.1 * in the superclass as starting points. */ 74 cananian 1.1.2.1 private void do_one(HClass hc) { 75 cananian 1.3.2.1 assert hc!=null; 76 cananian 1.1.2.1 // get the 'free space' structure of the parent. 77 cananian 1.3.2.2 List<Interval> free = new LinkedList<Interval> 78 cananian 1.3.2.2 (Arrays.asList(freespace(hc.getSuperclass()))); 79 cananian 1.1.2.1 // get all the fields of this class that we have to allocate. 80 cananian 1.3.2.2 List<HField> l = 81 cananian 1.3.2.2 new ArrayList<HField>(Arrays.asList(hc.getDeclaredFields())); 82 cananian 1.1.2.1 // weed out static fields 83 cananian 1.3.2.2 for (Iterator<HField> it=l.iterator(); it.hasNext(); ) 84 cananian 1.3.2.2 if (it.next().isStatic()) 85 cananian 1.1.2.1 it.remove(); 86 cananian 1.1.2.1 // we're going to allocate fields from largest to smallest, 87 cananian 1.1.2.1 // so sort them first. (primarily sort by size, then by alignment) 88 cananian 1.3.2.2 Collections.sort(l, new Comparator<HField>() { 89 cananian 1.3.2.2 public int compare(HField hf1, HField hf2) { 90 cananian 1.1.2.1 // note reversed comparison here so that largest end up first. 91 cananian 1.1.2.1 int r = fieldSize(hf2) - fieldSize(hf1); 92 cananian 1.1.2.1 if (r==0) r = fieldAlignment(hf2) - fieldAlignment(hf1); 93 cananian 1.1.2.1 return r; 94 cananian 1.1.2.1 } 95 cananian 1.1.2.1 }); 96 cananian 1.1.2.1 // now allocate them one by one (largest to smallest, like we said) 97 cananian 1.1.2.1 // the alloc_one method has the side effect of adding an entry to 98 cananian 1.1.2.1 // the fieldcache. 99 cananian 1.3.2.2 for (Iterator<HField> it=l.iterator(); it.hasNext(); ) 100 cananian 1.3.2.2 alloc_one(it.next(), free); 101 cananian 1.1.2.1 // cache away the free list for the next guy (subclasses of this) 102 cananian 1.3.2.2 freecache.put(hc, free.toArray(new Interval[free.size()])); 103 cananian 1.1.2.1 // done! 104 cananian 1.1.2.1 } 105 cananian 1.1.2.1 /** this method tries to allocate the field hf as low in the object 106 cananian 1.1.2.1 * as possible, using the current list of free spaces in the class. */ 107 cananian 1.3.2.2 private void alloc_one(HField hf, List<Interval> free) { 108 cananian 1.1.2.1 int size = fieldSize(hf), align = fieldAlignment(hf); 109 cananian 1.1.2.1 // go through free list, looking for a place to put this. 110 cananian 1.3.2.2 for (ListIterator<Interval> li = free.listIterator(); li.hasNext(); ) { 111 cananian 1.3.2.2 Interval i = li.next(); 112 cananian 1.3.2.1 assert i.low < i.high; // validity of interval. 113 cananian 1.1.2.1 // l and h will be the boundaries of the field, if we put it 114 cananian 1.1.2.1 // in this interval. 115 cananian 1.1.2.1 int l = i.low; 116 cananian 1.1.2.1 if ((l%align)!=0) l+= align - (l % align); 117 cananian 1.1.2.1 int h = l + size; 118 cananian 1.1.2.1 if (h <= i.high) { // yay, the field fits here! 119 cananian 1.1.2.1 // update interval list. 120 cananian 1.1.2.1 Interval bot = new Interval(i.low, l); 121 cananian 1.1.2.1 Interval top = new Interval(h, i.high); 122 cananian 1.1.2.1 li.remove(); // replace the old interval with the split ones 123 cananian 1.1.2.1 if (bot.low < bot.high) li.add(bot); 124 cananian 1.1.2.1 if (top.low < top.high) li.add(top); 125 cananian 1.1.2.1 // cache field offset. 126 cananian 1.1.2.1 fieldcache.put(hf, new Integer(l)); 127 cananian 1.1.2.1 // done! 128 cananian 1.1.2.1 return; 129 cananian 1.1.2.1 } 130 cananian 1.1.2.1 } 131 cananian 1.1.2.1 // the last interval goes to infinity; we should always be able to 132 cananian 1.1.2.1 // allocate at the end of the object (ie never get to this point) 133 cananian 1.1.2.1 throw new Error("Should never get here!"); 134 cananian 1.1.2.1 } 135 cananian 1.1.2.1 /** maps fields to already-computed offsets */ 136 cananian 1.3.2.2 private final Map<HField,Integer> fieldcache = 137 cananian 1.3.2.2 new HashMap<HField,Integer>(); 138 cananian 1.1.2.1 139 cananian 1.1.2.1 /** this method returns the cached 'free space' list for class hc. 140 cananian 1.1.2.1 * if the free space list for hc has not already been created and 141 cananian 1.1.2.1 * cached, invokes do_one(hc) to create and cache it. hc==null 142 cananian 1.1.2.1 * indicates the "non-existent superclass of everything", and 143 cananian 1.1.2.1 * naturally fields can be allocated anywhere in it. This is 144 cananian 1.1.2.1 * represented as the interval [0, infinity). */ 145 cananian 1.1.2.1 private Interval[] freespace(HClass hc) { 146 cananian 1.1.2.1 if (hc==null) 147 cananian 1.1.2.1 return new Interval[] { new Interval(0, Integer.MAX_VALUE) }; 148 cananian 1.1.2.1 if (!freecache.containsKey(hc)) do_one(hc); 149 cananian 1.3.2.1 assert freecache.containsKey(hc); 150 cananian 1.3.2.2 return freecache.get(hc); 151 cananian 1.1.2.1 } 152 cananian 1.1.2.1 /** maps classes to 'free space' lists. */ 153 cananian 1.3.2.2 private final Map<HClass,Interval[]> freecache = 154 cananian 1.3.2.2 new HashMap<HClass,Interval[]>(); 155 cananian 1.1.2.1 156 cananian 1.1.2.1 /** This class represents an open interval in the class, which we 157 cananian 1.1.2.1 * may assign a field to (if it fits). */ 158 cananian 1.1.2.1 private static class Interval { 159 cananian 1.1.2.1 final int low, high; 160 cananian 1.1.2.1 Interval(int low, int high) { this.low = low; this.high=high; } 161 cananian 1.1.2.1 } 162 cananian 1.2 }