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