1 cananian 1.1.4.1  // ObjectBuilder.java, created Mon Oct 11 18:56:52 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.Runtime1;
  5 cananian 1.1.4.1  
  6 cananian 1.1.4.1  import harpoon.Backend.Generic.Runtime.ObjectBuilder.Info;
  7 cananian 1.1.4.1  import harpoon.Backend.Generic.Runtime.ObjectBuilder.ArrayInfo;
  8 cananian 1.1.4.1  import harpoon.Backend.Generic.Runtime.ObjectBuilder.ObjectInfo;
  9 cananian 1.1.4.1  import harpoon.Backend.Maps.FieldMap;
 10 cananian 1.1.4.1  import harpoon.Backend.Maps.NameMap;
 11 cananian 1.1.4.1  import harpoon.ClassFile.HClass;
 12 cananian 1.1.4.1  import harpoon.ClassFile.HField;
 13 cananian 1.1.4.1  import harpoon.IR.Tree.Exp;
 14 cananian 1.1.4.1  import harpoon.IR.Tree.Stm;
 15 cananian 1.1.4.1  import harpoon.IR.Tree.TreeFactory;
 16 cananian 1.1.4.2  import harpoon.IR.Tree.ALIGN;
 17 cananian 1.1.4.1  import harpoon.IR.Tree.CONST;
 18 cananian 1.1.4.4  import harpoon.IR.Tree.DATUM;
 19 cananian 1.1.4.1  import harpoon.IR.Tree.LABEL;
 20 cananian 1.1.4.1  import harpoon.IR.Tree.NAME;
 21 cananian 1.1.4.1  import harpoon.IR.Tree.SEGMENT;
 22 cananian 1.1.4.1  import harpoon.Temp.Label;
 23 cananian 1.1.4.10 import harpoon.Util.ArrayIterator;
 24 cananian 1.1.4.1  import harpoon.Util.Util;
 25 cananian 1.1.4.1  
 26 cananian 1.1.4.1  import java.util.ArrayList;
 27 cananian 1.3.2.4  import java.util.Collections;
 28 cananian 1.1.4.1  import java.util.Iterator;
 29 cananian 1.1.4.1  import java.util.List;
 30 cananian 1.1.4.5  import java.util.Random;
 31 cananian 1.1.4.1  /**
 32 cananian 1.1.4.1   * <code>ObjectBuilder</code> is an implementation of
 33 cananian 1.1.4.1   * <code>harpoon.Backend.Generic.Runtime.ObjectBuilder</code> for the
 34 cananian 1.1.4.1   * <code>Runtime1</code> runtime.
 35 cananian 1.1.4.10  * <p>
 36 cananian 1.1.4.10  * To accomodate transformations which add fields to
 37 cananian 1.1.4.10  * <code>java.lang.Object</code>, this
 38 cananian 1.1.4.10  * <code>Runtime.ObjectBuilder</code> initializes all fields of
 39 cananian 1.1.4.10  * <code>Object</code> with <code>null</code>, rather than attempting
 40 cananian 1.1.4.10  * to consult the given <code>Info</code> for them.  If other behavior
 41 cananian 1.1.4.10  * is eventually needed, it is a custom <code>RootOracle</code> be
 42 cananian 1.1.4.10  * defined and provided to the constructor which will be consulted on
 43 cananian 1.1.4.10  * the value of every field *before* any <code>Info</code>.
 44 cananian 1.1.4.10  * This provides for extensibility without direct code modifications
 45 cananian 1.1.4.10  * to the various parts of <code>Runtime1</code> which use this
 46 cananian 1.1.4.10  * <code>ObjectBuilder</code>.
 47 cananian 1.1.4.1   * 
 48 cananian 1.1.4.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 49 cananian 1.8       * @version $Id: ObjectBuilder.java,v 1.8 2004/02/08 03:20:58 cananian Exp $
 50 cananian 1.1.4.1   */
 51 cananian 1.1.4.1  public class ObjectBuilder
 52 cananian 1.1.4.1      extends harpoon.Backend.Generic.Runtime.ObjectBuilder {
 53 cananian 1.3.2.2      protected final Runtime runtime;
 54 cananian 1.3.2.2      protected final boolean pointersAreLong;
 55 cananian 1.3.2.2      protected final RootOracle ro;
 56 cananian 1.3.2.2      protected final Random rnd;
 57 cananian 1.3.2.2      protected final HClass HCobject; // cache HClass for java.lang.Object
 58 cananian 1.1.4.1  
 59 cananian 1.1.4.10     /** Creates a <code>ObjectBuilder</code> with a <code>RootOracle</code>
 60 cananian 1.1.4.10      *  which supplies <code>null</code> values to any field of
 61 cananian 1.1.4.10      *  <code>java.lang.Object</code> (which there usually aren't any of).
 62 cananian 1.1.4.10      */
 63 cananian 1.1.4.1      public ObjectBuilder(Runtime runtime) {
 64 cananian 1.1.4.10         this(runtime, new RootOracle() {
 65 bdemsky  1.1.4.16             public long counter=1;
 66 cananian 1.1.4.10             public Object get(HField hf, Info addlinfo) {
 67 cananian 1.1.4.10               if (hf.getDeclaringClass().getName().equals("java.lang.Object"))
 68 bdemsky  1.1.4.16                   if (hf.getName().equals("UID")) {
 69 bdemsky  1.1.4.16                       System.out.println("NI: "+addlinfo.type().getName().replace('.','/')+" "+(counter));
 70 bdemsky  1.1.4.16                       return new Long(counter++);
 71 bdemsky  1.1.4.16                   }
 72 bdemsky  1.1.4.16                   else
 73 bdemsky  1.1.4.16                       return defaultValue(hf);// fields of Object initialized to 0
 74 cananian 1.1.4.10               else return NOT_A_VALUE;
 75 cananian 1.1.4.10             }
 76 cananian 1.1.4.10         });
 77 cananian 1.1.4.10     }
 78 cananian 1.1.4.10     /** Creates a <code>ObjectBuilder</code>. */
 79 cananian 1.1.4.10     public ObjectBuilder(Runtime runtime, RootOracle ro) {
 80 cananian 1.1.4.15         this.runtime = runtime;
 81 cananian 1.1.4.5          this.pointersAreLong = runtime.frame.pointersAreLong();
 82 cananian 1.1.4.10         this.ro = ro;
 83 cananian 1.1.4.17         this.rnd = new Random(1234/*runtime.frame.hashCode()*/);//repeatable?
 84 cananian 1.1.4.10         this.HCobject = runtime.frame.getLinker().forName("java.lang.Object");
 85 cananian 1.1.4.1      }
 86 cananian 1.1.4.1  
 87 cananian 1.1.4.1      public Stm buildObject(TreeFactory tf, ObjectInfo info,
 88 cananian 1.1.4.1                             boolean exported) {
 89 cananian 1.1.4.15         FieldMap cfm = ((TreeBuilder) runtime.getTreeBuilder()).cfm;
 90 cananian 1.3.2.1          assert !info.type().isArray();
 91 cananian 1.3.2.1          assert !info.type().isPrimitive();
 92 cananian 1.3.2.3          List<Stm> stmlist = new ArrayList<Stm>();
 93 cananian 1.1.4.1          // header
 94 cananian 1.1.4.1          stmlist.add(makeHeader(tf, info, exported));
 95 cananian 1.3.2.5          int startOffset = headerFinalOffset(info);
 96 cananian 1.1.4.1          // fields, in field order
 97 cananian 1.3.2.3          List<HField> l = cfm.fieldList(info.type());
 98 cananian 1.3.2.5          int endOffset = (l.size()==0) ? startOffset :
 99 cananian 1.3.2.4             cfm.fieldOffset(l.get(l.size()-1))+cfm.fieldSize(l.get(l.size()-1));
100 cananian 1.3.2.5          Stm s = makeFields(tf, info, l, startOffset, endOffset);
101 cananian 1.3.2.4          if (s!=null) stmlist.add(s);
102 cananian 1.1.4.1          // done -- ta da!
103 cananian 1.1.4.1          return Stm.toStm(stmlist);
104 cananian 1.1.4.1      }
105 cananian 1.1.4.1      public Stm buildArray(TreeFactory tf, ArrayInfo info,
106 cananian 1.1.4.1                            boolean exported) {
107 cananian 1.1.4.15         FieldMap cfm = ((TreeBuilder) runtime.getTreeBuilder()).cfm;
108 cananian 1.3.2.1          assert info.type().isArray();
109 cananian 1.1.4.1          HClass cType = info.type().getComponentType();
110 cananian 1.3.2.3          List<Stm> stmlist = new ArrayList<Stm>(info.length()+2);
111 cananian 1.1.4.1          // header
112 cananian 1.1.4.1          stmlist.add(makeHeader(tf, info, exported));
113 cananian 1.3.2.5          int startOffset = headerFinalOffset(info);
114 cananian 1.3.2.5          // fields of the object, including the length field. in order.
115 cananian 1.3.2.5          List<HField> l = cfm.fieldList(info.type());
116 cananian 1.3.2.5          assert l.size() > 0; // always at least the length field!
117 cananian 1.3.2.5          int endOffset =
118 cananian 1.3.2.4             cfm.fieldOffset(l.get(l.size()-1))+cfm.fieldSize(l.get(l.size()-1));
119 cananian 1.7              // always pad to pointer-size.
120 cananian 1.7              while (0 != (endOffset % (pointersAreLong?8:4)))
121 cananian 1.7                  endOffset++; // not the most efficient calculation, but readable.
122 cananian 1.3.2.5          Stm s = makeFields(tf, info, l, startOffset, endOffset);
123 cananian 1.3.2.5          assert s!=null; // always the length!
124 cananian 1.3.2.5          stmlist.add(s);
125 cananian 1.1.4.1          // data
126 cananian 1.1.4.1          for (int i=0; i<info.length(); i++)
127 cananian 1.1.4.1              stmlist.add(makeDatum(tf, info.get(i)));
128 cananian 1.1.4.1          // done -- ta da!
129 cananian 1.1.4.1          return Stm.toStm(stmlist);
130 cananian 1.1.4.1      }
131 cananian 1.3.2.4      private Object lookup(Info info, HField hf) {
132 cananian 1.1.4.10         Object o = ro.get(hf, info);
133 cananian 1.3.2.4          if (o != ro.NOT_A_VALUE) return o;
134 cananian 1.3.2.5          if (info instanceof ArrayInfo && hf.getName().equals("length"))
135 cananian 1.3.2.5              // XXX should wrap more precisely based on hf.getType().
136 cananian 1.3.2.5              // (arrays may have small length fields in future)
137 cananian 1.3.2.5              return new Integer(((ArrayInfo)info).length());
138 cananian 1.3.2.5          assert info instanceof ObjectInfo :
139 cananian 1.3.2.5              "field of array not given a value: "+hf+" / "+info;
140 cananian 1.3.2.4          return ((ObjectInfo)info).get(hf);
141 cananian 1.1.4.10     }
142 cananian 1.3.2.2      protected Stm makeHeader(TreeFactory tf, Info info, boolean exported)
143 cananian 1.1.4.1      {
144 cananian 1.3.2.3          List<Stm> stmlist = new ArrayList<Stm>(4);
145 cananian 1.6              // align to word boundary (double-word on 64-bit platforms)
146 cananian 1.6              stmlist.add(new ALIGN(tf, null, pointersAreLong ? 8 : 4));
147 cananian 1.1.4.1          // label:
148 cananian 1.1.4.1          stmlist.add(new LABEL(tf, null, info.label(), exported));
149 cananian 1.1.4.1          // claz pointer
150 cananian 1.1.4.15         stmlist.add(_DATUM(tf, runtime.getNameMap().label(info.type())));
151 cananian 1.1.4.3          // hash code.
152 cananian 1.1.4.5          // this is of pointer size, and must have the low bit set.  we *could*
153 cananian 1.1.4.5          // emit a symbolic reference to info.label()+1 or some such, but
154 cananian 1.1.4.5          // this would complicate the pattern-matching instruction selector.
155 cananian 1.1.4.5          // so instead we'll just select a random number of the right length
156 cananian 1.1.4.5          // and set the low bit.
157 cananian 1.1.4.5          stmlist.add(makeDatum(tf, pointersAreLong ?
158 cananian 1.1.4.5                                (Number) new Long(1 | rnd.nextLong()) :
159 cananian 1.1.4.5                                (Number) new Integer(1 | rnd.nextInt())));
160 cananian 1.1.4.1          // okay, done with header.
161 cananian 1.3.2.4          return Stm.toStm(stmlist);
162 cananian 1.3.2.4      }
163 cananian 1.3.2.5      protected int headerFinalOffset(Info info) { return 0; }
164 cananian 1.3.2.4      protected Stm makeFields(TreeFactory tf, Info info, List<HField> fields,
165 cananian 1.3.2.4                               int startOffset, int endOffset) {
166 cananian 1.3.2.4          assert endOffset >= startOffset;
167 cananian 1.3.2.4          FieldMap cfm = ((TreeBuilder) runtime.getTreeBuilder()).cfm;
168 cananian 1.3.2.4          List<Stm> stmlist = new ArrayList<Stm>(2*fields.size());
169 cananian 1.3.2.4          int offset = startOffset;
170 cananian 1.8              for (HField hf : fields) {
171 cananian 1.3.2.4              int thisOffset = cfm.fieldOffset(hf);
172 cananian 1.3.2.4              if (thisOffset<startOffset) continue; // ignore
173 cananian 1.3.2.4              if (thisOffset>endOffset) break; // done.
174 cananian 1.3.2.4              assert thisOffset >= offset : "fields in order";
175 cananian 1.3.2.4              if (thisOffset > offset) // handle padding
176 cananian 1.3.2.4                  stmlist.add(makePadding(tf, thisOffset-offset));
177 cananian 1.3.2.4              stmlist.add(makeDatum(tf, lookup(info, hf)));
178 cananian 1.3.2.4              offset = thisOffset+cfm.fieldSize(hf);
179 cananian 1.3.2.4          }
180 cananian 1.3.2.4          // final padding, if needed.
181 cananian 1.3.2.4          if (endOffset > offset)
182 cananian 1.3.2.4              stmlist.add(makePadding(tf, endOffset-offset));
183 cananian 1.3.2.4          // done -- ta da!
184 cananian 1.3.2.4          return Stm.toStm(stmlist); // MAY RETURN NULL.
185 cananian 1.3.2.4      }
186 cananian 1.3.2.4      Stm makePadding(TreeFactory tf, int bytes) {
187 cananian 1.3.2.4          List<Stm> stmlist = new ArrayList<Stm>();
188 cananian 1.3.2.4          while (bytes > 0)
189 cananian 1.3.2.4              if (bytes>=8) {
190 cananian 1.3.2.4                  stmlist.add(_DATUM(tf, new CONST(tf, null, (long)0)));
191 cananian 1.3.2.4                  bytes-=8;
192 cananian 1.3.2.4              } else if (bytes>=4) {
193 cananian 1.3.2.4                  stmlist.add(_DATUM(tf, new CONST(tf, null, (int)0)));
194 cananian 1.3.2.4                  bytes-=4;
195 cananian 1.3.2.4              } else if (bytes>=2) {
196 cananian 1.3.2.4                  stmlist.add(_DATUM(tf, new CONST(tf, null, 16, false, 0)));
197 cananian 1.3.2.4                  bytes-=2;
198 cananian 1.3.2.4              } else {
199 cananian 1.3.2.4                  stmlist.add(_DATUM(tf, new CONST(tf, null, 8, false, 0)));
200 cananian 1.3.2.4                  bytes-=1;
201 cananian 1.3.2.4              }
202 cananian 1.3.2.4          // small-to-big
203 cananian 1.3.2.4          Collections.reverse(stmlist);
204 cananian 1.3.2.4          // done!
205 cananian 1.1.4.1          return Stm.toStm(stmlist);
206 cananian 1.1.4.1      }
207 cananian 1.1.4.1      Stm makeDatum(TreeFactory tf, Object datum) {
208 cananian 1.1.4.7          if (datum==null)
209 cananian 1.1.4.7              return _DATUM(tf, new CONST(tf, null)); // null constant.
210 cananian 1.1.4.7          else if (datum instanceof Integer)
211 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null,
212 cananian 1.1.4.1                                     ((Integer)datum).intValue()));
213 cananian 1.1.4.1          else if (datum instanceof Long)
214 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null,
215 cananian 1.1.4.1                                     ((Long)datum).longValue()));
216 cananian 1.1.4.1          else if (datum instanceof Float)
217 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null,
218 cananian 1.1.4.1                                     ((Float)datum).floatValue()));
219 cananian 1.1.4.1          else if (datum instanceof Double)
220 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null,
221 cananian 1.1.4.1                                     ((Double)datum).doubleValue()));
222 cananian 1.1.4.1          else if (datum instanceof Boolean)
223 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null, 8, false,
224 cananian 1.1.4.1                                     ((Boolean)datum).booleanValue()?1:0));
225 cananian 1.1.4.1          else if (datum instanceof Byte)
226 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null, 8, true,
227 cananian 1.1.4.1                                     ((Byte)datum).intValue()));
228 cananian 1.1.4.1          else if (datum instanceof Short)
229 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null,16, true,
230 cananian 1.1.4.1                                     ((Short)datum).intValue()));
231 cananian 1.1.4.1          else if (datum instanceof Character)
232 cananian 1.1.4.4              return _DATUM(tf, new CONST(tf, null,16, false,
233 cananian 1.1.4.1                                     ((Character)datum).charValue()));
234 cananian 1.1.4.1          else if (datum instanceof Info)
235 cananian 1.1.4.4              return _DATUM(tf, ((Info)datum).label());
236 cananian 1.1.4.4          else throw new Error("ILLEGAL DATUM TYPE");
237 cananian 1.1.4.1      }
238 cananian 1.1.4.4      DATUM _DATUM(TreeFactory tf, Exp e) { 
239 cananian 1.1.4.4          return new DATUM(tf, null, e); 
240 cananian 1.1.4.1      }
241 cananian 1.1.4.4      DATUM _DATUM(TreeFactory tf, Label l) {
242 cananian 1.1.4.4          return new DATUM(tf,null,new NAME(tf,null,l));
243 bdemsky  1.1.4.12     }
244 bdemsky  1.1.4.12 
245 bdemsky  1.1.4.12     /** utility function copied from Interpret/Quads/Ref.java */
246 bdemsky  1.1.4.12     static final Object defaultValue(HField f) {
247 bdemsky  1.1.4.12         if (f.isConstant()) return f.getConstant();
248 bdemsky  1.1.4.12         return defaultValue(f.getType());
249 bdemsky  1.1.4.12     }
250 bdemsky  1.1.4.12     static final Object defaultValue(HClass ty) {
251 bdemsky  1.1.4.12         if (!ty.isPrimitive()) return null;
252 bdemsky  1.1.4.12         if (ty == HClass.Boolean) return new Boolean(false);
253 bdemsky  1.1.4.12         if (ty == HClass.Byte) return new Byte((byte)0);
254 bdemsky  1.1.4.12         if (ty == HClass.Char) return new Character((char)0);
255 bdemsky  1.1.4.12         if (ty == HClass.Double) return new Double(0);
256 bdemsky  1.1.4.12         if (ty == HClass.Float) return new Float(0);
257 bdemsky  1.1.4.12         if (ty == HClass.Int) return new Integer(0);
258 bdemsky  1.1.4.12         if (ty == HClass.Long) return new Long(0);
259 bdemsky  1.1.4.12         if (ty == HClass.Short) return new Short((short)0);
260 bdemsky  1.1.4.12         throw new Error("Ack!  What kinda default value is this?!");
261 cananian 1.1.4.10     }
262 cananian 1.1.4.10 
263 cananian 1.1.4.10 
264 cananian 1.1.4.10     /** A <code>RootOracle</code> allows a transformation to add
265 cananian 1.1.4.10      *  fields to <code>java.lang.Object</code> (or any other
266 cananian 1.1.4.10      *  class, really) and provide the initial values for that
267 cananian 1.1.4.10      *  field in the various runtime constant objects without
268 cananian 1.1.4.10      *  having to directly extend every <code>ObjectInfo</code>
269 cananian 1.1.4.10      *  used in this <code>Generic.Runtime</code> implementation.
270 cananian 1.1.4.10      *  The <code>RootOracle</code> will be consulted for the
271 cananian 1.1.4.10      *  value of every field *before* the <code>ObjectInfo</code>,
272 cananian 1.1.4.10      *  allowing an override -- if no override is desired, the
273 cananian 1.1.4.10      *  <code>RootOracle.get()</code> method should return
274 cananian 1.1.4.10      *  <code>NOT_A_VALUE</code>.
275 cananian 1.1.4.10      */
276 salcianu 1.5          public static abstract class RootOracle implements java.io.Serializable {
277 cananian 1.1.4.10         /** This is the constant value returned which this
278 cananian 1.1.4.10          *  oracle doesn't wish to override the given field. */
279 cananian 1.1.4.10         public static final Object NOT_A_VALUE = new Object();
280 cananian 1.1.4.10         /** Returns the override value of the given field <code>hf</code>
281 cananian 1.1.4.10          *  (more information about the object in question is
282 cananian 1.1.4.10          *   provided by <code>addlinfo</code>); if this
283 cananian 1.1.4.10          *   <code>RootOracle</code> doesn't wish to override this
284 cananian 1.1.4.10          *   field, it should return the constant <code>NOT_A_VALUE</code>.
285 cananian 1.1.4.10          */
286 cananian 1.1.4.10         public abstract Object get(HField hf, Info addlinfo);
287 cananian 1.1.4.1      }
288 cananian 1.2      }