1 cananian 1.1.2.1 // TinyClassFieldMap.java, created Fri Mar 15 19:21:30 2002 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.RuntimeTiny;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.Backend.Analysis.ClassFieldMap;
  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 
 10 cananian 1.1.2.1 import java.util.ArrayList;
 11 cananian 1.1.2.1 import java.util.Arrays;
 12 cananian 1.1.2.1 import java.util.Collections;
 13 cananian 1.1.2.1 import java.util.Comparator;
 14 cananian 1.1.2.1 import java.util.HashMap;
 15 cananian 1.1.2.1 import java.util.Iterator;
 16 cananian 1.1.2.1 import java.util.List;
 17 cananian 1.1.2.1 import java.util.Map;
 18 cananian 1.1.2.1 /**
 19 cananian 1.1.2.1  * <code>TinyClassFieldMap</code> is an extension of <code>ClassFieldMap</code>
 20 cananian 1.1.2.1  * which lays out objects *attempting* to align them, but not forcing an
 21 cananian 1.1.2.1  * alignment.
 22 cananian 1.1.2.1  * 
 23 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 24 cananian 1.3      * @version $Id: TinyClassFieldMap.java,v 1.3 2004/02/08 03:21:01 cananian Exp $
 25 cananian 1.1.2.1  */
 26 cananian 1.1.2.1 public abstract class TinyClassFieldMap extends ClassFieldMap {
 27 cananian 1.1.2.2     final int first_alignment;
 28 cananian 1.1.2.1     
 29 cananian 1.1.2.1     /** Creates a <code>TinyClassFieldMap</code>. */
 30 cananian 1.1.2.2     public TinyClassFieldMap() { this(0); }
 31 cananian 1.1.2.2     /** Creates a <code>TinyClassFieldMap</code>. */
 32 cananian 1.1.2.2     public TinyClassFieldMap(int first_alignment) {
 33 cananian 1.1.2.2         this.first_alignment = first_alignment;
 34 cananian 1.1.2.2     }
 35 cananian 1.1.2.1 
 36 cananian 1.1.2.1     /** Use this function to indicate a *preferred* but not *mandatory*
 37 cananian 1.1.2.1      *  alignment for the given field.  We will "try hard" to honor this
 38 cananian 1.1.2.1      *  alignment, but not if it would mean increasing the object size. */
 39 cananian 1.1.2.1     public int fieldPreferredAlignment(HField hf){ return fieldAlignment(hf); }
 40 cananian 1.1.2.1 
 41 cananian 1.1.2.1     private final Map<HClass,HField[]> cache = new HashMap<HClass,HField[]>();
 42 cananian 1.1.2.1     protected HField[] declaredFields(HClass hc) {
 43 cananian 1.1.2.1         if (!cache.containsKey(hc)) {
 44 cananian 1.1.2.1             // determine the alignment of the last field of the superclass.
 45 cananian 1.1.2.2             int alignment=first_alignment;
 46 cananian 1.1.2.1             HClass sc = hc.getSuperclass();
 47 cananian 1.1.2.1             if (sc!=null) {
 48 cananian 1.1.2.1                 List<HField> l = fieldList(sc);
 49 cananian 1.1.2.1                 if (l.size()>0) {
 50 cananian 1.1.2.1                     HField lastfield = l.get(l.size()-1);
 51 cananian 1.1.2.1                     alignment = fieldOffset(lastfield)+fieldSize(lastfield);
 52 cananian 1.1.2.1                 }
 53 cananian 1.1.2.1             }
 54 cananian 1.1.2.1             // make list of non-static fields.
 55 cananian 1.1.2.1             List<HField> l =
 56 cananian 1.1.2.1                 new ArrayList<HField>(Arrays.asList(hc.getDeclaredFields()));
 57 cananian 1.1.2.1             for (Iterator<HField> it=l.iterator(); it.hasNext(); )
 58 cananian 1.1.2.1                 if (it.next().isStatic())
 59 cananian 1.1.2.1                     it.remove();
 60 cananian 1.1.2.1             // sort declared fields by max(preferredalignment,alignment,size)
 61 cananian 1.1.2.1             // (largest first)
 62 cananian 1.1.2.1             Collections.sort(l, new Comparator<HField>() {
 63 cananian 1.1.2.1                 public int compare(HField hf1, HField hf2) {
 64 cananian 1.1.2.1                     int align1 = Math.max(fieldPreferredAlignment(hf1),
 65 cananian 1.1.2.1                                           fieldAlignment(hf1));
 66 cananian 1.1.2.1                     int align2 = Math.max(fieldPreferredAlignment(hf2),
 67 cananian 1.1.2.1                                           fieldAlignment(hf2));
 68 cananian 1.1.2.1                     return Math.max(fieldSize(hf2),align2)
 69 cananian 1.1.2.1                         - Math.max(fieldSize(hf1),align1);
 70 cananian 1.1.2.1                 }
 71 cananian 1.1.2.1             });
 72 cananian 1.1.2.1             // make our result list
 73 cananian 1.1.2.1             List<HField> result = new ArrayList<HField>(l.size());
 74 cananian 1.1.2.1             // while we have more fields to order:
 75 cananian 1.1.2.1             while (!l.isEmpty()) {
 76 cananian 1.1.2.1                 HField selectedField = null;
 77 cananian 1.1.2.1                 // find the largest aligned *must-align* field.
 78 cananian 1.1.2.1                 // (a must-align field has fieldAlignment>1)
 79 cananian 1.1.2.1                 for (Iterator<HField> it=l.iterator();
 80 cananian 1.1.2.1                      selectedField==null && it.hasNext(); ) {
 81 cananian 1.1.2.1                     HField hf = it.next();
 82 cananian 1.1.2.2                     // hack to skip fields which cross the header boundary
 83 cananian 1.1.2.2                     if (alignment<0 && alignment+fieldSize(hf)>0) continue;
 84 cananian 1.1.2.1                     if (fieldAlignment(hf) > 1 &&
 85 cananian 1.1.2.1                         0 == (alignment % fieldAlignment(hf))) {
 86 cananian 1.1.2.1                         selectedField = hf;
 87 cananian 1.1.2.1                         it.remove();
 88 cananian 1.1.2.1                     }
 89 cananian 1.1.2.1                 }
 90 cananian 1.1.2.1                 // else, find the largest preferably-aligned field.
 91 cananian 1.1.2.1                 for (Iterator<HField> it=l.iterator();
 92 cananian 1.1.2.1                      selectedField==null && it.hasNext(); ) {
 93 cananian 1.1.2.1                     HField hf = it.next();
 94 cananian 1.1.2.2                     // hack to skip fields which cross the header boundary
 95 cananian 1.1.2.2                     if (alignment<0 && alignment+fieldSize(hf)>0) continue;
 96 cananian 1.1.2.1                     if (0 == (alignment % fieldPreferredAlignment(hf))) {
 97 cananian 1.1.2.1                         selectedField = hf;
 98 cananian 1.1.2.1                         it.remove();
 99 cananian 1.1.2.1                     }
100 cananian 1.1.2.1                 }
101 cananian 1.1.2.1                 // otherwise find the smallest unaligned field.
102 cananian 1.1.2.1                 if (selectedField==null)
103 cananian 1.1.2.1                     selectedField = l.remove(l.size()-1);
104 cananian 1.1.2.2                 // hack to protect the header boundary.
105 cananian 1.1.2.2                 if (alignment<0 && alignment+fieldSize(selectedField)>0)
106 cananian 1.1.2.2                     alignment=0;
107 cananian 1.1.2.1                 // okay, add the selected field to the result, update alignment
108 cananian 1.1.2.1                 result.add(selectedField);
109 cananian 1.1.2.1                 while (0 != (alignment % fieldAlignment(selectedField)))
110 cananian 1.1.2.1                     alignment++;
111 cananian 1.1.2.1                 alignment += fieldSize(selectedField);
112 cananian 1.1.2.1             }
113 cananian 1.1.2.1             // done.
114 cananian 1.1.2.1             cache.put(hc, result.toArray(new HField[result.size()]));
115 cananian 1.1.2.1         }
116 cananian 1.1.2.1         return cache.get(hc);
117 cananian 1.1.2.1     }
118 cananian 1.1.2.2     // XXX copied from superclass, but hacked to deal with first_alignment.
119 cananian 1.1.2.2     public int fieldOffset(HField hf) {
120 cananian 1.1.2.2         assert hf!=null && !hf.isStatic();
121 cananian 1.1.2.2         if (!cache2.containsKey(hf)) {
122 cananian 1.1.2.2             int offset=first_alignment;
123 cananian 1.3                 for (HField nexthf : fieldList(hf.getDeclaringClass())) {
124 cananian 1.1.2.2                 // hack to protect the header boundary
125 cananian 1.1.2.2                 if (offset<0 && offset+fieldSize(nexthf)>0)
126 cananian 1.1.2.2                     offset=0;
127 cananian 1.1.2.2                 // end hack
128 cananian 1.1.2.2                 int align = fieldAlignment(nexthf);
129 cananian 1.1.2.2                 assert align>0;
130 cananian 1.1.2.2                 if ((offset % align) != 0)
131 cananian 1.1.2.2                     offset += align - (offset%align);
132 cananian 1.1.2.2                 assert (offset % align) == 0;
133 cananian 1.1.2.2                 if (!cache2.containsKey(nexthf))
134 cananian 1.1.2.2                     cache2.put(nexthf, new Integer(offset));
135 cananian 1.1.2.2                 offset+=fieldSize(nexthf);
136 cananian 1.1.2.2             }
137 cananian 1.1.2.2         }
138 cananian 1.1.2.2         assert cache2.containsKey(hf) : hf+" not in fieldList()";
139 cananian 1.1.2.2         return cache2.get(hf).intValue();
140 cananian 1.1.2.2     }
141 cananian 1.1.2.2     private final Map<HField,Integer> cache2 = new HashMap<HField,Integer>();
142 cananian 1.2     }