1 cananian 1.1.4.1 // ClassFieldMap.java, created Sun Oct 10 19:30:33 1999 by cananian
  2 cananian 1.1.4.1 // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.4.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.4.1 package harpoon.Backend.Analysis;
  5 cananian 1.1.4.1 
  6 cananian 1.1.4.1 import harpoon.ClassFile.HClass;
  7 cananian 1.1.4.1 import harpoon.ClassFile.HField;
  8 cananian 1.1.4.1 import harpoon.Util.HClassUtil;
  9 cananian 1.6     import net.cscott.jutil.UnmodifiableListIterator;
 10 cananian 1.1.4.1 import harpoon.Util.Util;
 11 cananian 1.1.4.1 
 12 cananian 1.1.4.1 import java.util.AbstractSequentialList;
 13 cananian 1.1.4.1 import java.util.HashMap;
 14 cananian 1.1.4.1 import java.util.Iterator;
 15 cananian 1.1.4.1 import java.util.List;
 16 cananian 1.1.4.1 import java.util.ListIterator;
 17 cananian 1.1.4.1 import java.util.Map;
 18 cananian 1.1.4.1 import java.util.NoSuchElementException;
 19 cananian 1.1.4.1 /**
 20 cananian 1.1.4.1  * A <code>ClassFieldMap</code> is a <code>FieldMap</code> for
 21 cananian 1.1.4.1  * non-static fields of a class.  The user must implement a function
 22 cananian 1.1.4.1  * giving the size of a field to complete the implementation.
 23 cananian 1.1.4.1  * Results are cached for efficiency.
 24 cananian 1.1.4.1  * 
 25 cananian 1.1.4.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 26 cananian 1.7      * @version $Id: ClassFieldMap.java,v 1.7 2004/02/08 03:20:42 cananian Exp $
 27 cananian 1.1.4.1  */
 28 cananian 1.1.4.1 public abstract class ClassFieldMap extends harpoon.Backend.Maps.FieldMap {
 29 cananian 1.1.4.1     /** Creates a <code>ClassFieldMap</code>. */
 30 cananian 1.1.4.1     public ClassFieldMap() { /* no special initialization. */ }
 31 cananian 1.1.4.2 
 32 cananian 1.1.4.1     // caching version of method inherited from superclass.
 33 cananian 1.1.4.1     public int fieldOffset(HField hf) {
 34 cananian 1.3.2.1         assert hf!=null && !hf.isStatic();
 35 cananian 1.1.4.1         if (!cache.containsKey(hf)) {
 36 cananian 1.1.4.1             int offset=0;
 37 cananian 1.7                 for (HField nexthf : fieldList(hf.getDeclaringClass())) {
 38 cananian 1.1.4.2                 int align = fieldAlignment(nexthf);
 39 cananian 1.3.2.1                 assert align>0;
 40 cananian 1.1.4.2                 if ((offset % align) != 0)
 41 cananian 1.1.4.2                     offset += align - (offset%align);
 42 cananian 1.3.2.1                 assert (offset % align) == 0;
 43 cananian 1.1.4.1                 if (!cache.containsKey(nexthf))
 44 cananian 1.1.4.1                     cache.put(nexthf, new Integer(offset));
 45 cananian 1.1.4.1                 offset+=fieldSize(nexthf);
 46 cananian 1.1.4.1             }
 47 cananian 1.1.4.1         }
 48 cananian 1.3.2.1         assert cache.containsKey(hf) : hf+" not in fieldList()";
 49 cananian 1.3.2.2         return cache.get(hf).intValue();
 50 cananian 1.1.4.1     }
 51 cananian 1.3.2.2     private final Map<HField,Integer> cache = new HashMap<HField,Integer>();
 52 cananian 1.1.4.1 
 53 cananian 1.1.4.1     // the meat of this class: return non-static fields in order, from
 54 cananian 1.1.4.1     // top-most superclass down.
 55 cananian 1.3.2.2     public List<HField> fieldList(final HClass hc) {
 56 cananian 1.3.2.1         assert hc!=null;
 57 cananian 1.1.4.1         // first calculate size of list.
 58 cananian 1.1.4.1         int n=0;
 59 cananian 1.1.4.1         for (HClass hcp=hc; hcp!=null; hcp=hcp.getSuperclass()) {
 60 cananian 1.1.4.3             HField[] fields = declaredFields(hcp);
 61 cananian 1.1.4.1             for (int i=0; i<fields.length; i++)
 62 cananian 1.1.4.1                 if (!fields[i].isStatic()) n++;
 63 cananian 1.1.4.1         }
 64 cananian 1.1.4.1         final int size = n;
 65 cananian 1.1.4.1         // now make & return list object.
 66 cananian 1.3.2.2         return new AbstractSequentialList<HField>() {
 67 cananian 1.1.4.1             public int size() { return size; }
 68 cananian 1.3.2.2             public ListIterator<HField> listIterator(final int index) {
 69 cananian 1.3.2.2                 return new UnmodifiableListIterator<HField>() {
 70 cananian 1.1.4.1                     final HClass[] parents = HClassUtil.parents(hc);
 71 cananian 1.1.4.1                     HField[] fields;
 72 cananian 1.1.4.1                     int pindex, findex, xindex;
 73 cananian 1.1.4.1                     boolean done=true, forwards;
 74 cananian 1.1.4.1                     {   // initialization code: count from beginning or end
 75 cananian 1.1.4.1                         // depending on which is closer.
 76 cananian 1.1.4.1                         if (index < size/2) { // count from beginning.
 77 cananian 1.1.4.1                             pindex=0;
 78 cananian 1.1.4.3                             fields = declaredFields(parents[pindex]);
 79 cananian 1.1.4.1                             findex=-1; forwards=true;
 80 cananian 1.1.4.1                             for (xindex=-1; xindex < index; xindex++)
 81 cananian 1.1.4.1                                 advance();
 82 cananian 1.1.4.1                         } else { // count from end.
 83 cananian 1.1.4.1                             pindex = parents.length-1;
 84 cananian 1.1.4.3                             fields = declaredFields(parents[pindex]);
 85 cananian 1.1.4.1                             findex=fields.length; forwards=true;
 86 cananian 1.1.4.1                             for (xindex=size; xindex > index; xindex--)
 87 cananian 1.1.4.1                                 retreat();
 88 cananian 1.1.4.1                         }
 89 cananian 1.1.4.1                     }
 90 cananian 1.1.4.1                     public boolean hasNext() {
 91 cananian 1.1.4.1                         if (!forwards) changeDirection();
 92 cananian 1.1.4.1                         return !done;
 93 cananian 1.1.4.1                     }
 94 cananian 1.1.4.1                     public boolean hasPrevious() {
 95 cananian 1.1.4.1                         if (forwards) changeDirection();
 96 cananian 1.1.4.1                         return !done;
 97 cananian 1.1.4.1                     }
 98 cananian 1.3.2.2                     public HField next() {
 99 cananian 1.1.4.1                         if (!forwards) changeDirection();
100 cananian 1.1.4.1                         if (done) throw new NoSuchElementException();
101 cananian 1.1.4.1                         xindex++;
102 cananian 1.1.4.1                         HField hf = fields[findex]; advance(); return hf;
103 cananian 1.1.4.1                     }
104 cananian 1.3.2.2                     public HField previous() {
105 cananian 1.1.4.1                         if (forwards) changeDirection();
106 cananian 1.1.4.1                         if (done) throw new NoSuchElementException();
107 cananian 1.1.4.1                         xindex--;
108 cananian 1.1.4.1                         HField hf = fields[findex]; retreat(); return hf;
109 cananian 1.1.4.1                     }
110 cananian 1.1.4.1                     public int nextIndex() { return xindex; }
111 cananian 1.1.4.1                     private void advance() {
112 cananian 1.1.4.1                         done=false;
113 cananian 1.1.4.1                         while (true) {
114 cananian 1.1.4.1                             for (findex++; findex < fields.length; findex++)
115 cananian 1.1.4.1                                 if (!fields[findex].isStatic()) return;
116 cananian 1.1.4.1                             if (++pindex >= parents.length) break;
117 cananian 1.1.4.3                             fields = declaredFields(parents[pindex]);
118 cananian 1.1.4.1                             findex = -1;
119 cananian 1.1.4.1                         }
120 cananian 1.1.4.1                         --pindex; done=true;
121 cananian 1.1.4.1                     }
122 cananian 1.1.4.1                     private void retreat() {
123 cananian 1.1.4.1                         done=false;
124 cananian 1.1.4.1                         while (true) {
125 cananian 1.1.4.1                             for (findex--; findex >= 0; findex--)
126 cananian 1.1.4.1                                 if (!fields[findex].isStatic()) return;
127 cananian 1.1.4.1                             if (--pindex < 0) break;
128 cananian 1.1.4.3                             fields = declaredFields(parents[pindex]);
129 cananian 1.1.4.1                             findex = fields.length;
130 cananian 1.1.4.1                         }
131 cananian 1.1.4.1                         ++pindex; done=true;
132 cananian 1.1.4.1                     }
133 cananian 1.1.4.1                     private void changeDirection() {
134 cananian 1.1.4.1                         if (forwards) retreat(); else advance();
135 cananian 1.1.4.1                         forwards = !forwards;
136 cananian 1.1.4.1                     }
137 cananian 1.1.4.1                 };
138 cananian 1.1.4.1             }
139 cananian 1.1.4.1         };
140 cananian 1.1.4.3     }
141 cananian 1.1.4.3     /** Return the declared fields of the specified class in the
142 cananian 1.1.4.3      *  order in which they should be allocated.  This implementation
143 cananian 1.1.4.3      *  just returns the result of <code>hc.getDeclaredFields()</code>,
144 cananian 1.1.4.3      *  but you can override this to use a more intelligent sorting
145 cananian 1.1.4.3      *  routine to save space. You do not have to filter static methods
146 cananian 1.1.4.3      *  out of the returned array, but you may if you like. */
147 cananian 1.1.4.3     protected HField[] declaredFields(HClass hc) {
148 cananian 1.1.4.3         return hc.getDeclaredFields();
149 cananian 1.1.4.1     }
150 cananian 1.2     }