001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.ssa;
014    
015    import java.util.ArrayList;
016    import java.util.Enumeration;
017    import java.util.HashMap;
018    import java.util.HashSet;
019    import java.util.Iterator;
020    import java.util.Set;
021    import org.jikesrvm.VM;
022    import org.jikesrvm.classloader.RVMField;
023    import org.jikesrvm.classloader.FieldReference;
024    import org.jikesrvm.classloader.TypeReference;
025    import org.jikesrvm.compilers.opt.OperationNotImplementedException;
026    import org.jikesrvm.compilers.opt.ir.ALoad;
027    import org.jikesrvm.compilers.opt.ir.AStore;
028    import org.jikesrvm.compilers.opt.ir.BBend;
029    import org.jikesrvm.compilers.opt.ir.GetField;
030    import org.jikesrvm.compilers.opt.ir.GetStatic;
031    import org.jikesrvm.compilers.opt.ir.GuardedUnary;
032    import org.jikesrvm.compilers.opt.ir.Label;
033    import org.jikesrvm.compilers.opt.ir.BasicBlock;
034    import org.jikesrvm.compilers.opt.ir.IR;
035    import org.jikesrvm.compilers.opt.ir.Instruction;
036    import org.jikesrvm.compilers.opt.ir.Operators;
037    import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH_opcode;
038    import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_ADDR_opcode;
039    import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_INT_opcode;
040    import static org.jikesrvm.compilers.opt.ir.Operators.BBEND_opcode;
041    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode;
042    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode;
043    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD_opcode;
044    import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE_opcode;
045    import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
046    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode;
047    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode;
048    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD_opcode;
049    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE_opcode;
050    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode;
051    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode;
052    import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode;
053    import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode;
054    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode;
055    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode;
056    import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD_opcode;
057    import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE_opcode;
058    import static org.jikesrvm.compilers.opt.ir.Operators.LABEL_opcode;
059    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode;
060    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode;
061    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD_opcode;
062    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE_opcode;
063    import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode;
064    import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode;
065    import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_UNRESOLVED_opcode;
066    import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_opcode;
067    import static org.jikesrvm.compilers.opt.ir.Operators.NEWOBJMULTIARRAY_opcode;
068    import static org.jikesrvm.compilers.opt.ir.Operators.NEW_UNRESOLVED_opcode;
069    import static org.jikesrvm.compilers.opt.ir.Operators.NEW_opcode;
070    import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
071    import static org.jikesrvm.compilers.opt.ir.Operators.PHI_opcode;
072    import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_ADDR_opcode;
073    import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_INT_opcode;
074    import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode;
075    import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode;
076    import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING_opcode;
077    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
078    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
079    import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD_opcode;
080    import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE_opcode;
081    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode;
082    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode;
083    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD_opcode;
084    import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE_opcode;
085    import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
086    import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode;
087    import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD_opcode;
088    import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_BEGIN_opcode;
089    import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_END_opcode;
090    import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode;
091    import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD_opcode;
092    import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR_opcode;
093    import org.jikesrvm.compilers.opt.ir.Phi;
094    import org.jikesrvm.compilers.opt.ir.PutField;
095    import org.jikesrvm.compilers.opt.ir.PutStatic;
096    import org.jikesrvm.compilers.opt.ir.operand.BasicBlockOperand;
097    import org.jikesrvm.compilers.opt.ir.operand.HeapOperand;
098    import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
099    import org.jikesrvm.compilers.opt.ir.operand.Operand;
100    
101    /**
102     * An <code> SSADictionary </code> structure holds lookaside
103     * information regarding Heap Array SSA form for an IR.  The general idea
104     * is that all Heap Array SSA form information resides in this lookaside
105     * structure.  Note that this is not the case for scalar SSA information.
106     *
107     * <P> See our SAS 2000 paper
108     * <a href="http://www.research.ibm.com/jalapeno/publication.html#sas00">
109     *  Unified Analysis of Arrays and Object References in Strongly Typed
110     *  Languages </a> for an overview of Array SSA form.  More implementation
111     *  details are documented in {@link SSA <code> SSA.java </code>}.
112     *
113     * @see SSA
114     */
115    @SuppressWarnings("unchecked")
116    // Generic HeapOperands and HeapVariables make this
117    // impossible to typecheck properly
118    public final class SSADictionary {
119    
120      /**
121       * Flag to turn on debugging
122       */
123      private static final boolean DEBUG = false;
124    
125      /**
126       * The object for the heap variable that is used for modelling
127       * explicit exception dependencies
128       */
129      static final String exceptionState = "X-State";
130    
131      /**
132       * A mapping from <code> Instruction </code> to the set of heap
133       * operands (an <code> HeapOperand[]</code>) that this instruction
134       * uses.  Note that PHI instructions <STRONG> do not </STRONG> appear in
135       * this mapping.
136       */
137      private final HashMap<Instruction, HeapOperand<Object>[]> uses =
138          new HashMap<Instruction, HeapOperand<Object>[]>();
139    
140      /**
141       * A mapping from <code> Instruction </code> to the set of heap
142       * operands (an <code> HeapOperand[]</code>) that this instruction
143       * defines.  Note that PHI instructions <STRONG> do not </STRONG> appear in
144       * this mapping.
145       */
146      private final HashMap<Instruction, HeapOperand<Object>[]> defs =
147          new HashMap<Instruction, HeapOperand<Object>[]>();
148    
149      /**
150       * A mapping from <code> HeapKey </code> to the set of heap
151       * variables introduced for this IR
152       */
153      private final HashMap<HeapKey<Object>, HeapVariable<Object>> heapVariables =
154          new HashMap<HeapKey<Object>, HeapVariable<Object>>();
155    
156      /**
157       * A mapping from heap variable type to <code> Integer </code>
158       * This structure holds the next number to assign when creating
159       * a new heap variable name for a given type
160       */
161      private HashMap<Object, Integer> nextNumber = new HashMap<Object, Integer>();
162    
163      /**
164       * A mapping from <code> BasicBlock </code> to <code> ArrayList
165       * </code> of <code> Instruction </code>.
166       * This map holds the list of heap phi instructions stored as
167       * lookaside for each basic block.
168       */
169      private final HashMap<BasicBlock, ArrayList<Instruction>> heapPhi =
170          new HashMap<BasicBlock, ArrayList<Instruction>>(10);
171    
172      /**
173       * An empty vector, used for utility.
174       */
175      private static final ArrayList<Instruction> emptyArrayList = new ArrayList<Instruction>(0);
176    
177      /**
178       * A mapping from <code> HeapVariable </code> to <code> HashSet
179       * </code> of <code> HeapOperand </code>.
180       * This map holds the set of heap operands which use each heap
181       * variable.
182       */
183      private final HashMap<HeapVariable<Object>, HashSet<HeapOperand<Object>>> UseChain =
184          new HashMap<HeapVariable<Object>, HashSet<HeapOperand<Object>>>(10);
185    
186      /**
187       * A mapping from <code> HeapVariable </code> to <code> HeapOperand </code>.
188       * This map holds the set of heap operands which define each heap
189       * variable.
190       */
191      private final HashMap<HeapVariable<Object>, HeapOperand<Object>> DefChain =
192          new HashMap<HeapVariable<Object>, HeapOperand<Object>>(10);
193    
194      /**
195       * The set of instructions which have been registered to potentially
196       * exit the procedure
197       */
198      private final HashSet<Instruction> exits = new HashSet<Instruction>(10);
199    
200      /**
201       * A mapping from a heap variable type to a <code> HashSet
202       * </code> of <code> Instruction </code>.
203       * The set of all uses of a heap variable type
204       * <em> before </em> we performed renaming for SSA.
205       */
206      private final HashMap<Object, HashSet<HeapOperand<Object>>> originalUses =
207          new HashMap<Object, HashSet<HeapOperand<Object>>>(10);
208    
209      /**
210       * A mapping from a heap variable type to a <code> HashSet
211       * </code> of <code> Instruction </code>.
212       * The set of all definitions of a heap variable type
213       * <em> before </em> we performed renaming for SSA.
214       */
215      private final HashMap<Object, HashSet<HeapOperand<Object>>> originalDefs =
216          new HashMap<Object, HashSet<HeapOperand<Object>>>(10);
217    
218      /**
219       * The set of type to build heap array variables for
220       */
221      private final Set<Object> heapTypes;
222    
223      /**
224       * Should the heap array SSA form constructed include uphi functions?
225       * That is, does a <em> use </em> create a new name for a heap variable.
226       */
227      private final boolean uphi;
228    
229      /**
230       * Should PEIs and stores to the heap be modelled via an explicit exception
231       * state heap variable?
232       */
233      private final boolean insertPEIDeps;
234    
235      /**
236       * A pointer to the governing IR
237       */
238      private final IR ir;
239    
240      /**
241       * Initialize a structure to hold Heap Array SSA information.
242       *
243       * @param heapTypes only create heap arrays for these locations.
244       *                  if null, create all heap arrays
245       * @param uphi Should we use uphi functions? (ie. loads create a new
246       *                             name for heap arrays)
247       */
248      SSADictionary(Set<Object> heapTypes, boolean uphi, boolean insertPEIDeps, IR ir) {
249        this.heapTypes = heapTypes;
250        this.uphi = uphi;
251        this.insertPEIDeps = insertPEIDeps;
252        this.ir = ir;
253      }
254    
255      /**
256       * Does a particular instruction <em> use </em> any heap variable?
257       *
258       * @param s the instruction in question
259       * @return true iff the instruction uses any heap variable.  false
260       * otherwise
261       */
262      boolean usesHeapVariable(Instruction s) {
263        // special case code for Phi instructions
264        if (Phi.conforms(s)) {
265          Operand result = Phi.getResult(s);
266          return (result instanceof HeapOperand);
267        }
268        HeapOperand<Object>[] o = uses.get(s);
269        return (o != null);
270      }
271    
272      /**
273       * Does a particular instruction <em> define </em> any heap variable?
274       *
275       * @param s the instruction in question
276       * @return true iff the instruction defs any heap variable.  false
277       * otherwise
278       */
279      boolean defsHeapVariable(Instruction s) {
280        // special case code for Phi instructions
281        if (s.operator == PHI) {
282          Operand result = Phi.getResult(s);
283          return (result instanceof HeapOperand);
284        }
285        HeapOperand<Object>[] o = defs.get(s);
286        return (o != null);
287      }
288    
289      /**
290       * Return the heap operands used by an instruction.
291       *
292       * @param s the instruction in question
293       * @return an array of the heap operands this instruction uses
294       */
295      public HeapOperand<Object>[] getHeapUses(Instruction s) {
296        if (s.operator == PHI) {
297          if (!usesHeapVariable(s)) return null;
298          HeapOperand<Object>[] result = new HeapOperand[Phi.getNumberOfValues(s)];
299          for (int i = 0; i < result.length; i++) {
300            result[i] = (HeapOperand) Phi.getValue(s, i);
301          }
302          return result;
303        } else {
304          return uses.get(s);
305        }
306      }
307    
308      /**
309       * Return the heap operands defined by an instruction.
310       *
311       * @param s the instruction in question
312       * @return an array of the heap operands this instruction defs
313       */
314      public HeapOperand<Object>[] getHeapDefs(Instruction s) {
315        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
316        return defs.get(s);
317      }
318    
319      /**
320       * Return the number of heap operands defined by an instruction
321       *
322       * @param s the instruction in question
323       * @return the number of heap operands this instruction defs
324       */
325      int getNumberOfHeapDefs(Instruction s) {
326        return getHeapDefs(s).length;
327      }
328    
329      /**
330       * Replace all heap variables that an instruction defs with
331       * new heap variables.  Each new heap variable has the same
332       * type as the old one, but a new number.  Essentially, this
333       * function introduces new names required for translation
334       * into SSA form.  This instruction will be the single static
335       * definition for each new heap variable.
336       *
337       * @param s the instruction that writes to the new heap variables
338       * @param b the basic block containing <code> s </code>
339       * @return the new heap variables that the instruction defines
340       */
341      //@SuppressWarnings("unchecked")
342      HeapOperand<Object>[] replaceDefs(Instruction s, BasicBlock b) {
343        if (s.operator() == PHI) {
344          // Note that a PHI
345          // instruction defs exactly one heap variable, newH[0]
346          HeapOperand<Object> oldDef = (HeapOperand) Phi.getResult(s);
347          int number = getNextHeapVariableNumber(oldDef.getHeapType());
348          HeapOperand<Object>[] newH = new HeapOperand[1];
349          newH[0] = new HeapOperand<Object>(new HeapVariable<Object>(oldDef.getHeapType(), number, ir));
350          newH[0].setInstruction(s);
351          Phi.setResult(s, newH[0]);
352          // record the new heap definition
353          newH[0].getHeapVariable().registerDef(b);
354          if (DEBUG) System.out.println("New heap def " + newH[0] + " for " + s);
355          // store the new heap variable in relevant data structures
356          HeapKey<Object> key = new HeapKey<Object>(number, oldDef.getHeapType());
357          heapVariables.put(key, newH[0].getHeapVariable());
358          return newH;
359        } else {
360          // get old heap operands defined by this instruction
361          HeapOperand<Object>[] oldH = defs.get(s);
362          HeapOperand<Object>[] newH = new HeapOperand[oldH.length];
363          // for each old heap variable ..
364          for (int i = 0; i < oldH.length; i++) {
365            // create a new heap variable
366            int number = getNextHeapVariableNumber(oldH[i].getHeapType());
367            newH[i] = new HeapOperand<Object>(new HeapVariable<Object>(oldH[i].getHeapType(), number, ir));
368            newH[i].setInstruction(s);
369            // record the new heap definition
370            newH[i].getHeapVariable().registerDef(b);
371            if (DEBUG) System.out.println("New heap def " + newH[i] + " for " + s);
372            // store the new heap variable in relevant data structures
373            HeapKey<Object> key = new HeapKey<Object>(number, oldH[i].getHeapType());
374            heapVariables.put(key, newH[i].getHeapVariable());
375          }
376          // record the new heap variables this instruction defs
377          defs.put(s, newH);
378          return newH;
379        }
380      }
381    
382      /**
383       * Return an enumeration of the heap variables in this IR.
384       *
385       * @return the heap variables stored for this IR
386       */
387      Iterator<HeapVariable<Object>> getHeapVariables() {
388        return heapVariables.values().iterator();
389      }
390    
391      /**
392       * Return an enumeration of the control-phi functions for
393       * <em> Heap </em> variables at the beginning of a basic block.
394       *
395       * @param bb the basic block in question
396       * @return the phi instructions for heap variables at the beginning of
397       * the basic block
398       */
399      public Iterator<Instruction> getHeapPhiInstructions(BasicBlock bb) {
400        ArrayList<Instruction> v = heapPhi.get(bb);
401        if (v == null) {
402          return emptyArrayList.iterator();
403        }
404        return v.iterator();
405      }
406    
407      /**
408       * Return an enumeration of all instructions for a basic block, including
409       * the control-PHI functions for <em> heap </em> variables stored
410       * implicitly here.
411       *
412       * @param bb the basic block in question
413       * @return an enumeration of all instructions in this basic block,
414       * including heap phi instructions stored implicitly in this lookaside
415       * structure
416       */
417      AllInstructionEnumeration getAllInstructions(BasicBlock bb) {
418        return new AllInstructionEnumeration(bb, this);
419      }
420    
421      /**
422       * Return an enumeration of all uses of a particular heap variable.
423       *
424       * @param A the heap variable in question
425       * @return an iterator over all instructions that use this heap
426       * variable
427       */
428      Iterator<HeapOperand<Object>> iterateHeapUses(HeapVariable<Object> A) {
429        HashSet<HeapOperand<Object>> u = UseChain.get(A);
430        return u.iterator();
431      }
432    
433      /**
434       * Return the operand that represents a heap variable's unique def.
435       *
436       * @param A the heap variable in question
437       * @return the heap operand that represents this heap variable's unique
438       * static definition
439       */
440      HeapOperand<Object> getUniqueDef(HeapVariable<Object> A) {
441        return DefChain.get(A);
442      }
443    
444      /**
445       * Return an enumeration of all the original uses of a heap variable.
446       * That is, return an iteration of all uses of the heap variable
447       * <em> before </em> we performed renaming for SSA.
448       *
449       * @param A the heap variable in question
450       * @return an iteration of all instructions that used this heap
451       * variable, prior to renaming for SSA
452       */
453      @SuppressWarnings("unused")
454      // Useful for debugging ??
455      private Iterator<HeapOperand<Object>> iterateOriginalHeapUses(HeapVariable<Object> A) {
456        Object type = A.getHeapType();
457        HashSet<HeapOperand<Object>> set = findOrCreateOriginalUses(type);
458        return set.iterator();
459      }
460    
461      /**
462       * Return an enumeration of all the original definitions of a heap variable.
463       * That is, return an iteration of all defs of the heap variable
464       * <em> before </em> we performed renaming for SSA.
465       *
466       * @param A the heap variable in question
467       * @return an iteration of all instructions that defined this heap
468       * variable, prior to renaming for SSA
469       */
470      @SuppressWarnings("unused")
471      // Useful for debugging ??
472      private Iterator<HeapOperand<Object>> iterateOriginalHeapDefs(HeapVariable<Object> A) {
473        Object type = A.getHeapType();
474        HashSet<HeapOperand<Object>> set = findOrCreateOriginalDefs(type);
475        return set.iterator();
476      }
477    
478      /**
479       * Return a set of all the original uses of a heap variable.
480       * That is, return the set of all uses of the heap variable
481       * <em> before </em> we performed renaming for SSA.
482       *
483       * @param type   The heap variable in question
484       * @return the set of all instructions that used this heap
485       * variable, prior to renaming for SSA
486       */
487      private HashSet<HeapOperand<Object>> findOrCreateOriginalUses(Object type) {
488        HashSet<HeapOperand<Object>> result = originalUses.get(type);
489        if (result != null) {
490          return result;
491        }
492        // not found: create a new set
493        result = new HashSet<HeapOperand<Object>>(2);
494        for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) {
495          HeapVariable<Object> B = e.next();
496          if (B.getHeapType().equals(type)) {
497            HashSet<HeapOperand<Object>> u = UseChain.get(B);
498            result.addAll(u);
499          }
500        }
501        // store it in the hash set, and return
502        originalUses.put(type, result);
503        return result;
504      }
505    
506      /**
507       * Return a set of all the original definitions of a heap variable.
508       * That is, return the set of all uses of the heap variable
509       * <em> before </em> we performed renaming for SSA.
510       *
511       * @param type  the heap variable in question
512       * @return the set of all instructions that defined this heap
513       * variable, prior to renaming for SSA
514       */
515      private HashSet<HeapOperand<Object>> findOrCreateOriginalDefs(Object type) {
516        HashSet<HeapOperand<Object>> result = originalDefs.get(type);
517        if (result != null) {
518          return result;
519        }
520        // not found: create a new set
521        result = new HashSet<HeapOperand<Object>>(2);
522        for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) {
523          HeapVariable<Object> B = e.next();
524          if (B.getHeapType().equals(type)) {
525            HeapOperand<Object> def = getUniqueDef(B);
526            if (def != null) {
527              result.add(def);
528            }
529          }
530        }
531        // store it in the hash set, and return
532        originalDefs.put(type, result);
533        return result;
534      }
535    
536      /**
537       * Return the number of uses of a heap variable.
538       *
539       * @param A the heap variable in question
540       * @return the number of uses of the heap variable
541       */
542      int getNumberOfUses(HeapVariable<Object> A) {
543        HashSet<HeapOperand<Object>> u = UseChain.get(A);
544        return u.size();
545      }
546    
547      /**
548       * Return an enumeration of all heap variables that may be
549       * exposed on procedure exit.
550       *
551       * @return an enumeration of all heap variables that may be exposed on
552       * procedure exit
553       */
554      Iterator<HeapVariable<Object>> enumerateExposedHeapVariables() {
555        ArrayList<HeapVariable<Object>> v = new ArrayList<HeapVariable<Object>>();
556        for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) {
557          HeapVariable<Object> H = e.next();
558          if (isExposedOnExit(H)) {
559            v.add(H);
560          }
561        }
562        return v.iterator();
563      }
564    
565      /**
566       * Is heap variable H exposed on procedure exit?
567       *
568       * @return true or false as appropriate
569       */
570      boolean isExposedOnExit(HeapVariable<Object> H) {
571        for (Iterator<HeapOperand<Object>> i = iterateHeapUses(H); i.hasNext();) {
572          HeapOperand<Object> op = i.next();
573          Instruction s = op.instruction;
574          if (exits.contains(s)) {
575            return true;
576          }
577        }
578        return false;
579      }
580    
581      /**
582       * Recompute the chain of uses for each heap variable.
583       * NOTE: for now this procedure does <em> not </em> recompute
584       * def chains
585       */
586      void recomputeArrayDU() {
587        UseChain.clear();
588        DefChain.clear();
589        // create a set of uses for each heap variable
590        for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) {
591          HeapVariable<Object> H = e.next();
592          HashSet<HeapOperand<Object>> u = new HashSet<HeapOperand<Object>>(2);
593          UseChain.put(H, u);
594        }
595        // populate the use chain with each use registered
596        for (HeapOperand<Object>[] operands : uses.values()) {
597          if (operands == null) continue;
598          for (HeapOperand<Object> operand : operands) {
599            HeapVariable<Object> v = operand.getHeapVariable();
600            HashSet<HeapOperand<Object>> u = UseChain.get(v);
601            u.add(operand);
602          }
603        }
604        // record the unique def for each heap variable
605        for (HeapOperand<Object>[] operands : defs.values()) {
606          if (operands == null) continue;
607          for (HeapOperand<Object> operand : operands) {
608            HeapVariable<Object> v = operand.getHeapVariable();
609            DefChain.put(v, operand);
610          }
611        }
612        // handle each HEAP PHI function.
613        for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) {
614          BasicBlock bb = e.nextElement();
615          for (Iterator<Instruction> hp = getHeapPhiInstructions(bb); hp.hasNext();) {
616            Instruction phi = hp.next();
617            HeapOperand<Object> H = (HeapOperand) Phi.getResult(phi);
618            HeapVariable<Object> v = H.getHeapVariable();
619            DefChain.put(v, H);
620            for (int i = 0; i < Phi.getNumberOfValues(phi); i++) {
621              HeapOperand<Object> Hu = (HeapOperand) Phi.getValue(phi, i);
622              HeapVariable<Object> vu = Hu.getHeapVariable();
623              HashSet<HeapOperand<Object>> u = UseChain.get(vu);
624              u.add(Hu);
625            }
626          }
627        }
628      }
629    
630      /**
631       * Delete an HeapOperand from the use chain of its heap variable
632       *
633       * @param op the heap operand to be deleted
634       */
635      void deleteFromUseChain(HeapOperand<Object> op) {
636        HeapVariable<Object> hv = op.getHeapVariable();
637        HashSet<HeapOperand<Object>> u = UseChain.get(hv);
638        u.remove(op);
639      }
640    
641      /**
642       * Add an HeapOperand to the use chain of its heap variable
643       *
644       * @param op the heap operand to be added
645       */
646      void addToUseChain(HeapOperand<Object> op) {
647        HeapVariable<Object> hv = op.getHeapVariable();
648        HashSet<HeapOperand<Object>> u = UseChain.get(hv);
649        u.add(op);
650      }
651    
652      /**
653       * Create a heap control phi instruction, and store it at the
654       * beginning of a basic block.
655       *
656       * @param bb the basic block
657       * @param H the heap variable to merge
658       */
659      void createHeapPhiInstruction(BasicBlock bb, HeapVariable<Object> H) {
660        Instruction s = makePhiInstruction(H, bb);
661        /*
662        HeapOperand[] Hprime = new HeapOperand[1];
663        Hprime[0] = new HeapOperand(H);
664        Hprime[0].setInstruction(s);
665        defs.put(s, Hprime);
666        */
667        ArrayList<Instruction> heapPhis = heapPhi.get(bb);
668        if (heapPhis == null) {
669          heapPhis = new ArrayList<Instruction>(2);
670          heapPhi.put(bb, heapPhis);
671        }
672        heapPhis.add(s);
673        registerInstruction(s, bb);
674      }
675    
676      /**
677       * Register that an instruction now uses the set of heap operands
678       *
679       * @param s the instruction in question
680       * @param H the set of heap operands which s uses
681       */
682      void replaceUses(Instruction s, HeapOperand<Object>[] H) {
683        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
684        uses.put(s, H);
685        for (HeapOperand<Object> aH : H) {
686          aH.setInstruction(s);
687        }
688      }
689    
690      /**
691       * Return the total number of heap variables allocated for the IR
692       *
693       * @return the total number of heap variables allocated for the IR
694       */
695      int getNumberOfHeapVariables() {
696        return heapVariables.size();
697      }
698    
699      /**
700       * Register that an instruction s can potentially leave the procedure.
701       * We conservatively record that s uses all heap variables.
702       * <p> NOTE: This function should be called before renaming.
703       * <p> NOTE: Only need to use this for backwards analyses
704       *
705       * @param s the instruction in question
706       * @param b s's basic block
707       */
708      @SuppressWarnings("unchecked")
709      void registerExit(Instruction s, BasicBlock b) {
710        // setup an array of all heap variables
711        // TODO: for efficiency, cache a copy of 'all'
712        Iterator<HeapVariable<Object>> vars = heapVariables.values().iterator();
713        HeapOperand<Object>[] all = new HeapOperand[heapVariables.size()];
714        for (int i = 0; i < all.length; i++) {
715          all[i] = new HeapOperand<Object>(vars.next());
716          all[i].setInstruction(s);
717          // record that all[i] is def'ed in b
718          all[i].getHeapVariable().registerDef(b);
719        }
720        // record that s uses all heap variables
721        uses.put(s, all);
722        // record that instruction s can exit the procedure
723        exits.add(s);
724      }
725    
726      /**
727       * Register that an instruction s has unknown side effects.  That is,
728       * we conservatively record that s defs and uses all heap variables.
729       * <p> NOTE: This function should be called before renaming.
730       *
731       * @param s the instruction in question
732       * @param b the basic block containing s
733       */
734      @SuppressWarnings("unchecked")
735      void registerUnknown(Instruction s, BasicBlock b) {
736        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
737        // setup an array of all heap variables
738        // TODO: for efficiency, cache a copy of 'all'
739        Iterator vars = heapVariables.values().iterator();
740        HeapOperand<Object>[] all = new HeapOperand[heapVariables.size()];
741        for (int i = 0; i < all.length; i++) {
742          all[i] = new HeapOperand<Object>((HeapVariable<Object>) vars.next());
743          all[i].setInstruction(s);
744          // record that all[i] is def'ed in b
745          all[i].getHeapVariable().registerDef(b);
746        }
747        // record that s uses and defs all heap variables
748        uses.put(s, all);
749        defs.put(s, all);
750        // record that instruction s can exit the procedure
751        exits.add(s);
752      }
753    
754      /**
755       * Record the heap variables that instruction s defines and uses.
756       *
757       * @param s the instruction in question
758       * @param b the basic block containing s
759       */
760      void registerInstruction(Instruction s, BasicBlock b) {
761        if (!s.isImplicitLoad() &&
762            !s.isImplicitStore() &&
763            !s.isAllocation() &&
764            s.operator() != PHI &&
765            !(insertPEIDeps &&
766              (s.isPEI() ||
767               Label.conforms(s) ||
768               BBend.conforms(s) ||
769               s.operator.opcode == UNINT_BEGIN_opcode ||
770               s.operator.opcode == UNINT_END_opcode))) {
771          return;
772        }
773        // handled by registerUnknown
774        if (s.isDynamicLinkingPoint()) {
775          return;
776        }
777        switch (s.getOpcode()) {
778          case LABEL_opcode: // only reached if insertPEIDeps
779            labelHelper(s, b);
780            break;
781          case BBEND_opcode: // only reached if insertPEIDeps
782            bbendHelper(s, b);
783            break;
784          case UNINT_BEGIN_opcode: // only reached if insertPEIDeps
785          case UNINT_END_opcode: // only reached if insertPEIDeps
786            registerUse(s, exceptionState);
787            registerDef(s, b, exceptionState);
788            break;
789          case GETFIELD_opcode:
790            getFieldHelper(s, b);
791            break;
792          case PUTFIELD_opcode:
793            putFieldHelper(s, b);
794            break;
795          case GETSTATIC_opcode:
796            getStaticHelper(s, b);
797            break;
798          case PUTSTATIC_opcode:
799            putStaticHelper(s, b);
800            break;
801          case NEW_opcode:
802          case NEW_UNRESOLVED_opcode:
803            newHelper(s, b);
804            break;
805          case NEWARRAY_opcode:
806          case NEWARRAY_UNRESOLVED_opcode:
807            newArrayHelper(s, b);
808            break;
809          case NEWOBJMULTIARRAY_opcode:
810            /* SJF: after talking with Martin, I'm not sure what the
811             correct Array SSA representation for an allocation should
812             be.  Since we do not yet use these heap variables, do
813             nothing for now.
814             Future: this should probably def the heap variable for every
815             field of the object type allocated.
816             // treat this opcode like a CALL
817             registerUnknown(s,b);
818             */
819            break;
820          case INT_ALOAD_opcode:
821          case LONG_ALOAD_opcode:
822          case FLOAT_ALOAD_opcode:
823          case DOUBLE_ALOAD_opcode:
824          case REF_ALOAD_opcode:
825          case BYTE_ALOAD_opcode:
826          case UBYTE_ALOAD_opcode:
827          case USHORT_ALOAD_opcode:
828          case SHORT_ALOAD_opcode:
829            aloadHelper(s, b);
830            break;
831          case INT_ASTORE_opcode:
832          case LONG_ASTORE_opcode:
833          case FLOAT_ASTORE_opcode:
834          case DOUBLE_ASTORE_opcode:
835          case REF_ASTORE_opcode:
836          case BYTE_ASTORE_opcode:
837          case SHORT_ASTORE_opcode:
838            astoreHelper(s, b);
839            break;
840          case ARRAYLENGTH_opcode:
841            arraylengthHelper(s, b);
842            break;
843          case CALL_opcode:
844          case SYSCALL_opcode:
845          case MONITORENTER_opcode:
846          case MONITOREXIT_opcode:
847          case PREPARE_INT_opcode:
848          case PREPARE_ADDR_opcode:
849          case ATTEMPT_INT_opcode:
850          case ATTEMPT_ADDR_opcode:
851          case READ_CEILING_opcode:
852          case WRITE_FLOOR_opcode:
853            // do nothing: these cases handled by registerUnknown
854            break;
855          case UBYTE_LOAD_opcode:
856          case BYTE_LOAD_opcode:
857          case USHORT_LOAD_opcode:
858          case SHORT_LOAD_opcode:
859          case INT_LOAD_opcode:
860          case LONG_LOAD_opcode:
861          case DOUBLE_LOAD_opcode:
862          case REF_LOAD_opcode:
863            // !!TODO: how to handle this special case?
864            break;
865          case BYTE_STORE_opcode:
866          case SHORT_STORE_opcode:
867          case REF_STORE_opcode:
868          case INT_STORE_opcode:
869          case LONG_STORE_opcode:
870          case DOUBLE_STORE_opcode:
871            // !!TODO: how to handle this special case?
872            break;
873          case PHI_opcode:
874            phiHelper(s, b);
875            break;
876          default:
877            if (!Operators.helper.isHandledByRegisterUnknown(s.getOpcode()) && !s.isPEI()) {
878              System.out.println("SSA dictionary failed on " + s.toString());
879              throw new OperationNotImplementedException("SSADictionary: Unsupported opcode " + s);
880            }
881        }           // switch
882        if (insertPEIDeps) {
883          if (s.isImplicitStore()) addExceptionStateToUses(s);
884          if (s.isPEI()) addExceptionStateToDefs(s, b);
885        }
886      }
887    
888      /**
889       * Record the effects of a getfield instruction on the heap array
890       * SSA form.  Register the heap variables that this instruction uses and
891       * defs.  Note that if inserting uphi functions, a getfield defs a new
892       * heap variable name.
893       *
894       * @param s the getfield instruction
895       * @param b the basic block containing s
896       */
897      private void getFieldHelper(Instruction s, BasicBlock b) {
898        LocationOperand locOp = GetField.getLocation(s);
899        FieldReference field = locOp.getFieldRef();
900        registerUse(s, field);
901        if (uphi) {
902          registerDef(s, b, field);
903        }
904      }
905    
906      /**
907       * Record the effects of a putfield instruction on the heap array
908       * SSA form.  Register the heap variables that this instruction uses and
909       * defs.
910       *
911       * @param s the getfield instruction
912       * @param b the basic block containing s
913       */
914      private void putFieldHelper(Instruction s, BasicBlock b) {
915        LocationOperand locOp = PutField.getLocation(s);
916        FieldReference field = locOp.getFieldRef();
917        registerUse(s, field);
918        registerDef(s, b, field);
919      }
920    
921      /**
922       * Record the effects of a getstatic instruction on the heap array
923       * SSA form.  Register the heap variables that this instruction uses and
924       * defs.  Note that if inserting uphi functions, a getstatic defs a new
925       * heap variable name.
926       *
927       * @param s the getstatic instruction
928       * @param b the basic block containing s
929       */
930      private void getStaticHelper(Instruction s, BasicBlock b) {
931        LocationOperand locOp = GetStatic.getLocation(s);
932        FieldReference field = locOp.getFieldRef();
933        registerUse(s, field);
934        if (uphi) {
935          registerDef(s, b, field);
936        }
937      }
938    
939      /**
940       * Record the effects of a putstatic instruction on the heap array
941       * SSA form.  Register the heap variables that this instruction uses and
942       * defs.
943       *
944       * @param s the putstatic instruction
945       * @param b the basic block containing s
946       */
947      private void putStaticHelper(Instruction s, BasicBlock b) {
948        LocationOperand locOp = PutStatic.getLocation(s);
949        FieldReference field = locOp.getFieldRef();
950        registerUse(s, field);
951        registerDef(s, b, field);
952      }
953    
954      /**
955       * Update the heap array SSA form for an allocation instruction
956       *
957       * @param s the allocation instruction
958       * @param b the basic block containing the allocation
959       */
960      private void newHelper(Instruction s, BasicBlock b) {
961        /* SJF: after talking with Martin, I'm not sure what the
962        correct Array SSA representation for an allocation should
963        be.  Since we do not yet use these heap variables, do
964        nothing for now.
965        Future: this should probably def the heap variable for every
966        field of the object type allocated.
967        TypeOperand typeOp = New.getType(s);
968        RVMType type = typeOp.type;
969        registerUse(s,type);
970        registerDef(s,b,type);
971        */
972      }
973    
974      /**
975       * Update the heap array SSA form for an array allocation instruction
976       *
977       * @param s the allocation instruction
978       * @param b the basic block containing the allocation
979       */
980      private void newArrayHelper(Instruction s, BasicBlock b) {
981        // TODO: use some class hierarchy analysis
982        /* SJF: after talking with Martin, I'm not sure what the
983        correct Array SSA representation for an allocation should
984        be.  Since we do not yet use these heap variables, do
985        nothing for now.
986        Future: this should probably def the heap variable for every
987        field of the object type allocated.
988        TypeOperand typeOp = NewArray.getType(s);
989        RVMType type = typeOp.type;
990        if (!type.asArray().getElementType().isPrimitiveType())
991        type = ClassLoaderProxy.JavaLangObjectArrayType;
992        registerUse(s,type);
993        registerDef(s,b,type);
994        */
995      }
996    
997      /**
998       * Record the effects of a aload instruction on the heap array
999       * SSA form.  Register the heap variables that this instruction uses and
1000       * defs.  Note that if inserting uphi functions, a aload defs a new
1001       * heap variable name.
1002       *
1003       * @param s the aload instruction
1004       * @param b the basic block containing s
1005       */
1006      private void aloadHelper(Instruction s, BasicBlock b) {
1007        // TODO: use some class hierarchy analysis
1008        TypeReference type = ALoad.getArray(s).getType();
1009    
1010        // After cond branch splitting, operand may be a Null constant
1011        // filter out it now  -- Feng
1012        if (type.isArrayType()) {
1013          if (!type.getArrayElementType().isPrimitiveType()) {
1014            type = TypeReference.JavaLangObjectArray;
1015          }
1016          registerUse(s, type);
1017          if (uphi) {
1018            registerDef(s, b, type);
1019          }
1020        }
1021      }
1022    
1023      /**
1024       * Record the effects of an astore instruction on the heap array
1025       * SSA form.  Register the heap variables that this instruction uses and
1026       * defs.
1027       *
1028       * @param s the astore instruction
1029       * @param b the basic block containing s
1030       */
1031      private void astoreHelper(Instruction s, BasicBlock b) {
1032        // TODO: use some class hierarchy analysis
1033        TypeReference type = AStore.getArray(s).getType();
1034    
1035        // After cond branch splitting, operand may be a Null constant
1036        // filter out it now  -- Feng
1037        if (type.isArrayType()) {
1038          if (!type.getArrayElementType().isPrimitiveType()) {
1039            type = TypeReference.JavaLangObjectArray;
1040          }
1041          registerUse(s, type);
1042          registerDef(s, b, type);
1043        }
1044      }
1045    
1046      /**
1047       * Record the effects of an arraylength instruction on the heap array
1048       * SSA form.  Register the heap variable that this instruction uses.
1049       *
1050       * @param s the arraylength instruction
1051       * @param b the basic block containing s
1052       */
1053      private void arraylengthHelper(Instruction s, BasicBlock b) {
1054        // TODO: use some class hierarchy analysis
1055        TypeReference type = GuardedUnary.getVal(s).getType();
1056    
1057        // After cond branch splitting, operand may be a Null constant
1058        // filter it out now  -- Feng
1059        if (type.isArrayType()) {
1060          if (!type.getArrayElementType().isPrimitiveType()) {
1061            type = TypeReference.JavaLangObjectArray;
1062          }
1063          registerUse(s, type);
1064        }
1065      }
1066    
1067      /**
1068       * Record the effects of a phi instruction on the heap array
1069       * SSA form.  Register the heap variables that this instruction uses
1070       * and defs.
1071       *
1072       * @param s the phi instruction
1073       * @param b the basic block containing s
1074       */
1075      private void phiHelper(Instruction s, BasicBlock b) {
1076        // for phi function, we dont' register implicit defs and uses
1077        // since they're explicit in the instruction
1078        /*
1079        Object result = Phi.getResult(s);
1080        if (!(result instanceof HeapOperand))
1081          return;
1082        HeapOperand H = (HeapOperand)Phi.getResult(s);
1083        Object Htype = H.getHeapType();
1084        if (Htype instanceof RVMType) {
1085          RVMType t = (RVMType)Htype;
1086          registerDef(s, b, t);
1087        }
1088        else if (Htype instanceof RVMField) {
1089          RVMField f = (RVMField)Htype;
1090          registerDef(s, b, f);
1091        }
1092        else {
1093          String a = (String)Htype;
1094          registerDef(s, b, a);
1095        }
1096        for (int i = 0; i < Phi.getNumberOfValues(s); i++) {
1097          HeapOperand U = (HeapOperand)Phi.getValue(s, i);
1098          Object Utype = U.getHeapType();
1099          if (Utype instanceof RVMType) {
1100            RVMType t = (RVMType)Utype;
1101            registerUse(s, t);
1102          }
1103          else if (Utype instanceof RVMField) {
1104            RVMField f = (RVMField)Utype;
1105            registerUse(s, f);
1106          } else {
1107            String a = (String)Utype;
1108            registerUse(s, a);
1109          }
1110        }
1111      */
1112      }
1113    
1114      /**
1115       * Record the effects of a label instruction on the heap array
1116       * SSA form.  Register the exception state that this instruction defs.
1117       *
1118       * @param s the label instruction
1119       * @param b the basic block containing s
1120       */
1121      private void labelHelper(Instruction s, BasicBlock b) {
1122        Enumeration<BasicBlock> e = b.getIn();
1123        boolean newHandler = !e.hasMoreElements();
1124        while (!newHandler && e.hasMoreElements()) {
1125          if (!(e.nextElement().isExceptionHandlerEquivalent(b))) newHandler = true;
1126        }
1127        if (newHandler) registerDef(s, b, exceptionState);
1128      }
1129    
1130      /**
1131       * Record the effects of a bbend instruction on the heap array
1132       * SSA form.  Register the exception state that this instruction uses.
1133       *
1134       * @param s the label instruction
1135       * @param b the basic block containing s
1136       */
1137      private void bbendHelper(Instruction s, BasicBlock b) {
1138        Enumeration<BasicBlock> e = b.getOut();
1139        boolean newHandler = !e.hasMoreElements();
1140        while (!newHandler && e.hasMoreElements()) {
1141          if (!(e.nextElement().isExceptionHandlerEquivalent(b))) newHandler = true;
1142        }
1143        if (newHandler) registerUse(s, exceptionState);
1144      }
1145    
1146      /**
1147       * Register that an instruction uses a heap variable of a given
1148       * type.
1149       *
1150       * @param s the instruction in question
1151       * @param t the type of the heap variable the instruction uses
1152       */
1153      private void registerUse(Instruction s, TypeReference t) {
1154        // if the heapTypes set is defined, then we only build Array
1155        // SSA for these types.  So, ignore uses of types that are
1156        // not included in the set
1157        if (heapTypes != null) {
1158          if (!heapTypes.contains(t)) {
1159            return;
1160          }
1161        }
1162        HeapVariable<Object> H = findOrCreateHeapVariable(t);
1163        HeapOperand<Object>[] Hprime = new HeapOperand[1];
1164        Hprime[0] = new HeapOperand<Object>(H);
1165        Hprime[0].setInstruction(s);
1166        uses.put(s, Hprime);
1167      }
1168    
1169      /**
1170       * Register that an instruction writes a heap variable for a given
1171       * type.
1172       *
1173       * @param s the instruction in question
1174       * @param b s's basic block
1175       * @param t the type of the heap variable the instruction modifies
1176       */
1177      private void registerDef(Instruction s, BasicBlock b, TypeReference t) {
1178        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1179        // if the heapTypes set is defined, then we only build Array
1180        // SSA for these types.  So, ignore uses of types that are
1181        // not included in the set
1182        if (heapTypes != null) {
1183          if (!heapTypes.contains(t)) {
1184            return;
1185          }
1186        }
1187        HeapVariable<Object> H = findOrCreateHeapVariable(t);
1188        H.registerDef(b);
1189        HeapOperand<Object>[] Hprime = new HeapOperand[1];
1190        Hprime[0] = new HeapOperand<Object>(H);
1191        Hprime[0].setInstruction(s);
1192        defs.put(s, Hprime);
1193      }
1194    
1195      /**
1196       * Register that an instruction uses a heap variable for a given
1197       * field.
1198       *
1199       * @param s the instruction in question
1200       * @param fr the field heap variable the instruction uses
1201       */
1202      private void registerUse(Instruction s, FieldReference fr) {
1203        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1204        RVMField f = fr.peekResolvedField();
1205        HeapOperand<Object> H;
1206        if (f == null) {
1207          // can't resolve field at compile time.
1208          // This isn't quite correct, but is somewhat close.
1209          // See defect 3481.
1210          H = new HeapOperand<Object>(findOrCreateHeapVariable(fr));
1211        } else {
1212          // if the heapTypes set is defined, then we only build Array
1213          // SSA for these types.  So, ignore uses of types that are
1214          // not included in the set
1215          if (heapTypes != null) {
1216            if (!heapTypes.contains(f)) {
1217              return;
1218            }
1219          }
1220          H = new HeapOperand<Object>(findOrCreateHeapVariable(f));
1221        }
1222        HeapOperand<Object>[] Hprime = new HeapOperand[1];
1223        Hprime[0] = H;
1224        Hprime[0].setInstruction(s);
1225        uses.put(s, Hprime);
1226      }
1227    
1228      /**
1229       * Register that instruction <code>s</code> writes a heap variable for
1230       * a given field.
1231       *
1232       * @param s the instruction in question
1233       * @param b  <code>s</code>'s basic block
1234       * @param fr the field heap variable the instruction modifies
1235       */
1236      private void registerDef(Instruction s, BasicBlock b, FieldReference fr) {
1237        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1238        RVMField f = fr.peekResolvedField();
1239        HeapOperand<Object> H;
1240        if (f == null) {
1241          // can't resolve field at compile time.
1242          // This isn't quite correct, but is somewhat close.
1243          // See bug #1147433
1244          H = new HeapOperand<Object>(findOrCreateHeapVariable(fr));
1245        } else {
1246          // if the heapTypes set is defined, then we only build Array
1247          // SSA for these types.  So, ignore uses of types that are
1248          // not included in the set
1249          if (heapTypes != null) {
1250            if (!heapTypes.contains(f)) {
1251              return;
1252            }
1253          }
1254          H = new HeapOperand<Object>(findOrCreateHeapVariable(f));
1255        }
1256        H.value.registerDef(b);
1257        HeapOperand<Object>[] Hprime = new HeapOperand[1];
1258        Hprime[0] = H;
1259        Hprime[0].setInstruction(s);
1260        defs.put(s, Hprime);
1261      }
1262    
1263      /**
1264       * Register that an instruction uses a heap variable for a given
1265       * field.
1266       *
1267       * @param s the instruction in question
1268       * @param a the field heap variable the instruction uses
1269       */
1270      @SuppressWarnings("unchecked")
1271      private void registerUse(Instruction s, String a) {
1272        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1273        // if the heapTypes set is defined, then we only build Array
1274        // SSA for these types.  So, ignore uses of types that are
1275        // not included in the set
1276        if (heapTypes != null) {
1277          if (!heapTypes.contains(a)) {
1278            return;
1279          }
1280        }
1281        HeapVariable<Object> H = findOrCreateHeapVariable(a);
1282        HeapOperand<Object>[] Hprime = new HeapOperand[1];
1283        Hprime[0] = new HeapOperand<Object>(H);
1284        Hprime[0].setInstruction(s);
1285        uses.put(s, Hprime);
1286      }
1287    
1288      /**
1289       * Register that the instruction <code>s</code> writes a heap variable for
1290       * a given field.
1291       *
1292       * @param s the instruction in question
1293       * @param b <code>s</code>'s basic block
1294       * @param a  XXX TODO Check this XXX The field in question.
1295       */
1296      @SuppressWarnings("unchecked")
1297      private void registerDef(Instruction s, BasicBlock b, String a) {
1298        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1299        // if the heapTypes set is defined, then we only build Array
1300        // SSA for these types.  So, ignore uses of types that are
1301        // not included in the set
1302        if (heapTypes != null) {
1303          if (!heapTypes.contains(a)) {
1304            return;
1305          }
1306        }
1307        HeapVariable<Object> H = findOrCreateHeapVariable(a);
1308        H.registerDef(b);
1309        HeapOperand<Object>[] Hprime = new HeapOperand[1];
1310        Hprime[0] = new HeapOperand<Object>(H);
1311        Hprime[0].setInstruction(s);
1312        defs.put(s, Hprime);
1313      }
1314    
1315      /**
1316       * Returns a copy of H with an additional free slot at position 0
1317       *
1318       * @param H the array of HeapOperands to be extended.
1319       */
1320      @SuppressWarnings("unchecked")
1321      private static HeapOperand<Object>[] extendHArray(HeapOperand<Object>[] H) {
1322        HeapOperand<Object>[] res;
1323    
1324        if (H == null) {
1325          res = new HeapOperand[1];
1326        } else {
1327          res = new HeapOperand[H.length + 1];
1328          for (int i = 0; i < H.length; ++i) {
1329            res[i + 1] = H[i];
1330          }
1331        }
1332        return res;
1333      }
1334    
1335      /**
1336       * Register that an instruction defines the exception state.
1337       *
1338       * @param s the instruction in question
1339       * @param b s's basic block
1340       */
1341      @SuppressWarnings("unchecked")
1342      void addExceptionStateToDefs(Instruction s, BasicBlock b) {
1343        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1344        HeapVariable<Object> H = findOrCreateHeapVariable(exceptionState);
1345        H.registerDef(b);
1346        HeapOperand<Object>[] Hprime = extendHArray(defs.get(s));
1347        Hprime[0] = new HeapOperand<Object>(H);
1348        Hprime[0].setInstruction(s);
1349        defs.put(s, Hprime);
1350      }
1351    
1352      /**
1353       * Register that an instruction defines the exception state.
1354       *
1355       * @param s the instruction in question
1356       */
1357      @SuppressWarnings("unchecked")
1358      void addExceptionStateToUses(Instruction s) {
1359        if (VM.VerifyAssertions) VM._assert(s.operator != PHI);
1360        HeapVariable<Object> H = findOrCreateHeapVariable(exceptionState);
1361        HeapOperand<Object>[] Hprime = extendHArray(uses.get(s));
1362        Hprime[0] = new HeapOperand<Object>(H);
1363        Hprime[0].setInstruction(s);
1364        uses.put(s, Hprime);
1365      }
1366    
1367      /**
1368       * Return the heap variable for a given type or field with
1369       * number 0.
1370       * If no heap variable yet exits for this type or field, create a new
1371       * one.
1372       *
1373       * @param type the <code> TypeReference </code> or <code> RVMField </code>
1374       * identifying the desired heap variable
1375       * @return the desired heap variable
1376       */
1377      @SuppressWarnings("unchecked")
1378      private HeapVariable<Object> findOrCreateHeapVariable(Object type) {
1379        if (DEBUG) {
1380          System.out.print("findOrCreateHeapVariable " + type);
1381        }
1382        HeapKey<Object> key = new HeapKey<Object>(0, type);
1383        HeapVariable<Object> H = heapVariables.get(key);
1384        if (DEBUG) {
1385          System.out.println("...  found " + H);
1386        }
1387        if (H == null) {
1388          // note: if not found, then we have never created a heap
1389          // variable with the correct type. So, create one, with number
1390          // 0
1391          int number = getNextHeapVariableNumber(type);        // should return 0
1392          H = new HeapVariable<Object>(type, number, ir);
1393          heapVariables.put(key, H);
1394          if (DEBUG) {
1395            System.out.println("...  created " + heapVariables.get(key));
1396          }
1397        }
1398        return H;
1399      }
1400    
1401      /**
1402       * Get the next number to be assigned to a new heap variable
1403       * for a given type or field.
1404       *
1405       * @param type the <code> TypeReference </code> or <code> RVMField </code>
1406       * identifying the heap variable
1407       * @return the next integer (monotonically increasing) to identify a new
1408       * name for this heap variable
1409       */
1410      private int getNextHeapVariableNumber(Object type) {
1411        Integer current = nextNumber.get(type);
1412        if (current == null) {
1413          // no number found. Create one.
1414          Integer one = 1;
1415          nextNumber.put(type, one);
1416          return 0;
1417        }
1418        // bump up the number
1419        Integer next = current + 1;
1420        nextNumber.put(type, next);
1421        return current;
1422      }
1423    
1424      /**
1425       * Create a phi-function instruction for a heap variable
1426       *
1427       * @param H a symbolic variable for a Heap variable
1428       * @param bb the basic block holding the new phi function
1429       * instruction
1430       * @return the instruction <code> H = phi H,H,..,H </code>
1431       */
1432      private static Instruction makePhiInstruction(HeapVariable<Object> H, BasicBlock bb) {
1433        int n = bb.getNumberOfIn();
1434        Enumeration<BasicBlock> in = bb.getIn();
1435        HeapOperand<Object> lhs = new HeapOperand<Object>(H);
1436        Instruction s = Phi.create(PHI, lhs, n);
1437        lhs.setInstruction(s);
1438        for (int i = 0; i < n; i++) {
1439          HeapOperand<Object> op = new HeapOperand<Object>(H);
1440          op.setInstruction(s);
1441          Phi.setValue(s, i, op);
1442          BasicBlock pred = in.nextElement();
1443          Phi.setPred(s, i, new BasicBlockOperand(pred));
1444        }
1445        return s;
1446      }
1447    
1448      /**
1449       * This class represents the name of a heap variable in the heap array
1450       * SSA form.
1451       */
1452      private static final class HeapKey<T> {
1453        /**
1454         * The number and type comprise the name of a heap variable in array SSA
1455         * form
1456         */
1457        private final int number;
1458        /**
1459         * The number and type comprise the name of a heap variable in array SSA
1460         * form
1461         */
1462        private final T type;
1463    
1464        /**
1465         * Create a new name for a heap variable.
1466         *
1467         * @param     number the number, a unique integer from SSA renaming
1468         * @param     type   the type (a <code> RVMField </code> or <code>
1469         * TypeReference </code>
1470         */
1471        HeapKey(int number, T type) {
1472          this.number = number;
1473          this.type = type;
1474        }
1475    
1476        /**
1477         * Test against another key for equality.  This function is used to
1478         * retrive items from hashtables.
1479         *
1480         * @param key the object to compare with
1481         * @return {@code true} or {@code false} as appropriate
1482         */
1483        @Override
1484        public boolean equals(Object key) {
1485          if (!(key instanceof HeapKey)) {
1486            return false;
1487          }
1488          HeapKey<T> k = (HeapKey) key;
1489          return ((type.equals(k.type)) && (number == k.number));
1490        }
1491    
1492        /**
1493         * Return a hash code for this name.
1494         *
1495         * TODO: come up with a better hash function.
1496         *
1497         * @return the hash code
1498         */
1499        @Override
1500        public int hashCode() {
1501          return type.hashCode() + 8192 * number;
1502        }
1503      }
1504    
1505      /**
1506       * This class implements an <code> Enumeration </code> over all
1507       * instructions for a basic block. This enumeration includes
1508       * explicit instructions in the IR and implicit phi instructions
1509       * for heap variables, which are stored only in this lookaside
1510       * structure.
1511       */
1512      static final class AllInstructionEnumeration implements Enumeration<Instruction> {
1513        /**
1514         * An enumeration of the explicit instructions in the IR for a basic
1515         * block
1516         */
1517        private final Enumeration<Instruction> explicitInstructions;
1518    
1519        /**
1520         * An enumeration of the implicit instructions in the IR for a basic
1521         * block.  These instructions appear only in the SSA dictionary
1522         * lookaside structure.
1523         */
1524        private final Iterator<Instruction> implicitInstructions;
1525    
1526        /**
1527         * The label instruction for the basic block
1528         */
1529        private Instruction labelInstruction;
1530    
1531        /**
1532         * Construct an enumeration for all instructions, both implicit and
1533         * explicit in the IR, for a given basic block
1534         *
1535         * @param     bb the basic block whose instructions this enumerates
1536         */
1537        AllInstructionEnumeration(BasicBlock bb, SSADictionary dict) {
1538          explicitInstructions = bb.forwardInstrEnumerator();
1539          implicitInstructions = dict.getHeapPhiInstructions(bb);
1540          labelInstruction = explicitInstructions.nextElement();
1541        }
1542    
1543        /**
1544         * Are there more elements in the enumeration?
1545         *
1546         * @return {@code true} or {@code false}
1547         */
1548        @Override
1549        public boolean hasMoreElements() {
1550          return (implicitInstructions.hasNext() || explicitInstructions.hasMoreElements());
1551        }
1552    
1553        /**
1554         * Get the next instruction in the enumeration
1555         *
1556         * @return the next instruction
1557         */
1558        @Override
1559        public Instruction nextElement() {
1560          if (labelInstruction != null) {
1561            Instruction temp = labelInstruction;
1562            labelInstruction = null;
1563            return temp;
1564          }
1565          if (implicitInstructions.hasNext()) {
1566            return implicitInstructions.next();
1567          }
1568          return explicitInstructions.nextElement();
1569        }
1570      }
1571    }