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.ir;
014    
015    import java.util.Enumeration;
016    import java.util.Iterator;
017    import org.jikesrvm.ArchitectureSpecificOpt;
018    import org.jikesrvm.ArchitectureSpecificOpt.PhysicalDefUse;
019    import org.jikesrvm.classloader.TypeReference;
020    import org.jikesrvm.compilers.opt.ir.operand.HeapOperand;
021    import org.jikesrvm.compilers.opt.ir.operand.Operand;
022    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
023    
024    import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
025    import org.vmmagic.pragma.NoInline;
026    
027    /**
028     * This class is not meant to be instantiated.<p>
029     * It simply serves as a place to collect the implementation of
030     * primitive IR enumerations.<p>
031     * None of these functions are meant to be called directly from
032     * anywhere except IR, Instruction, and BasicBlock.<p>
033     * General clients should use the higher level interfaces provided
034     * by those classes.
035     */
036    public abstract class IREnumeration {
037    
038      /**
039       * Forward intra basic block instruction enumerations from
040       * from start...last inclusive.<p>
041       *
042       * NB: start and last _must_ be in the same basic block
043       *     and must be in the proper relative order.
044       *     This code does _not_ check this invariant, and will
045       *     simply fail by eventually thowing a NoSuchElementException
046       *     if it is not met. Caller's must be sure the invariants are met.
047       *
048       * @param start the instruction to start with
049       * @param end   the instruction to end with
050       * @return an enumeration of the instructions from start to end
051       */
052      public static Enumeration<Instruction> forwardIntraBlockIE(final Instruction start, final Instruction end) {
053        return new Enumeration<Instruction>() {
054          private Instruction current = start;
055          private final Instruction last = end;
056    
057          @Override
058          public boolean hasMoreElements() { return current != null; }
059    
060          @Override
061          public Instruction nextElement() {
062            Instruction res = current;
063            if (current == last) {
064              current = null;
065            } else {
066              try {
067                current = current.getNext();
068              } catch (NullPointerException e) {
069                fail("forwardIntraBlockIE");
070              }
071            }
072            return res;
073          }
074        };
075      }
076    
077      /**
078       * Reverse intra basic block instruction enumerations from
079       * from start...last inclusive.<p>
080       *
081       * NB: start and last _must_ be in the same basic block
082       *     and must be in the proper relative order.
083       *     This code does _not_ check this invariant, and will
084       *     simply fail by eventually thowing a NoSuchElementException
085       *     if it is not met. Caller's must be sure the invariants are met.
086       *
087       * @param start the instruction to start with
088       * @param end   the instruction to end with
089       * @return an enumeration of the instructions from start to end
090       */
091      public static Enumeration<Instruction> reverseIntraBlockIE(final Instruction start, final Instruction end) {
092        return new Enumeration<Instruction>() {
093          private Instruction current = start;
094          private final Instruction last = end;
095    
096          @Override
097          public boolean hasMoreElements() { return current != null; }
098    
099          @Override
100          public Instruction nextElement() {
101            Instruction res = current;
102            if (current == last) {
103              current = null;
104            } else {
105              try {
106                current = current.getPrev();
107              } catch (NullPointerException e) {
108                fail("reverseIntraBlockIE");
109              }
110            }
111            return res;
112          }
113        };
114      }
115    
116      /**
117       * A forward enumeration of all the instructions in the IR.
118       *
119       * @param ir the IR to walk over
120       * @return a forward enumeration of the insturctions in ir
121       */
122      public static Enumeration<Instruction> forwardGlobalIE(final IR ir) {
123        return new Enumeration<Instruction>() {
124          private Instruction current = ir.firstInstructionInCodeOrder();
125    
126          @Override
127          public boolean hasMoreElements() { return current != null; }
128    
129          @Override
130          public Instruction nextElement() {
131            try {
132              Instruction res = current;
133              current = current.nextInstructionInCodeOrder();
134              return res;
135            } catch (NullPointerException e) {
136              fail("forwardGlobalIR");
137              return null; // placate jikes
138            }
139          }
140        };
141      }
142    
143      /**
144       * A reverse enumeration of all the instructions in the IR.
145       *
146       * @param ir the IR to walk over
147       * @return a forward enumeration of the insturctions in ir
148       */
149      public static Enumeration<Instruction> reverseGlobalIE(final IR ir) {
150        return new Enumeration<Instruction>() {
151          private Instruction current = ir.lastInstructionInCodeOrder();
152    
153          @Override
154          public boolean hasMoreElements() { return current != null; }
155    
156          @Override
157          public Instruction nextElement() {
158            try {
159              Instruction res = current;
160              current = current.prevInstructionInCodeOrder();
161              return res;
162            } catch (NullPointerException e) {
163              fail("forwardGlobalIR");
164              return null; // placate jikes
165            }
166          }
167        };
168      }
169    
170      /**
171       * A forward enumeration of all the basic blocks in the IR.
172       *
173       * @param ir the IR to walk over
174       * @return a forward enumeration of the basic blocks in ir
175       */
176      public static Enumeration<BasicBlock> forwardBE(final IR ir) {
177        return new Enumeration<BasicBlock>() {
178          private BasicBlock current = ir.firstBasicBlockInCodeOrder();
179    
180          @Override
181          public boolean hasMoreElements() { return current != null; }
182    
183          @Override
184          public BasicBlock nextElement() {
185            try {
186              BasicBlock res = current;
187              current = current.nextBasicBlockInCodeOrder();
188              return res;
189            } catch (NullPointerException e) {
190              fail("forwardBE");
191              return null; // placate jikes
192            }
193          }
194        };
195      }
196    
197      /**
198       * A reverse enumeration of all the basic blocks in the IR.
199       *
200       * @param ir the IR to walk over
201       * @return a reverse enumeration of the basic blocks in ir
202       */
203      public static Enumeration<BasicBlock> reverseBE(final IR ir) {
204        return new Enumeration<BasicBlock>() {
205          private BasicBlock current = ir.lastBasicBlockInCodeOrder();
206    
207          @Override
208          public boolean hasMoreElements() { return current != null; }
209    
210          @Override
211          public BasicBlock nextElement() {
212            try {
213              BasicBlock res = current;
214              current = current.prevBasicBlockInCodeOrder();
215              return res;
216            } catch (NullPointerException e) {
217              fail("forwardBE");
218              return null; // placate jikes
219            }
220          }
221        };
222      }
223    
224      /**
225       * This class implements an enumeration of instructions over
226       * all instructions for a basic block. This enumeration includes
227       * explicit instructions in the IR and implicit phi instructions for
228       * heap variables, which are stored only in this lookaside
229       * structure.
230       * @see org.jikesrvm.compilers.opt.ssa.SSADictionary
231       */
232      public static final class AllInstructionsEnum implements Enumeration<Instruction> {
233        /**
234         * An enumeration of the explicit instructions in the IR for a
235         * basic block
236         */
237        private final Enumeration<Instruction> explicitInstructions;
238    
239        /**
240         * An enumeration of the implicit instructions in the IR for a
241         * basic block.  These instructions appear only in the SSA
242         * dictionary lookaside structure.
243         */
244        private final Iterator<Instruction> implicitInstructions;
245    
246        /**
247         * The label instruction for the basic block - the label is
248         * special as we want it to appear in the enumeration before the
249         * implicit SSA instructions
250         */
251        private Instruction labelInstruction;
252    
253        /**
254         * Construct an enumeration for all instructions, both implicit and
255         * explicit in the IR, for a given basic block
256         *
257         * @param block the basic block whose instructions this enumerates
258         */
259        public AllInstructionsEnum(IR ir, BasicBlock block) {
260          explicitInstructions = block.forwardInstrEnumerator();
261          if (ir.inSSAForm()) {
262            implicitInstructions = ir.HIRInfo.dictionary.getHeapPhiInstructions(block);
263          } else {
264            implicitInstructions = null;
265          }
266          labelInstruction = explicitInstructions.nextElement();
267        }
268    
269        /**
270         * Are there more elements in the enumeration?
271         *
272         * @return {@code true} or {@code false}
273         */
274        @Override
275        public boolean hasMoreElements() {
276          return (((implicitInstructions != null) && implicitInstructions.hasNext()) ||
277                  explicitInstructions.hasMoreElements());
278        }
279    
280        @Override
281        public Instruction nextElement() {
282          if (labelInstruction != null) {
283            Instruction temp = labelInstruction;
284            labelInstruction = null;
285            return temp;
286          } else if ((implicitInstructions != null) && implicitInstructions.hasNext()) {
287            return implicitInstructions.next();
288          } else {
289            return explicitInstructions.nextElement();
290          }
291        }
292      }
293    
294      /**
295       * This class implements an {@link Enumeration} of {@link Operand}s. It used
296       * for holding the definitions of a particular instruction and being
297       * used as an enumeration for iterating over. It differs from other
298       * enumerations of Operand as it iterates over both implicit
299       * and explicit operands.
300       * @see org.jikesrvm.compilers.opt.ssa.SSADictionary
301       */
302      public static final class AllDefsEnum implements Enumeration<Operand> {
303        /**
304         * Enumeration of non-heap operands defined by the instruction
305         */
306        private final Enumeration<Operand> instructionOperands;
307        /**
308         * Array of heap operands defined by the instruction
309         */
310        private final HeapOperand<?>[] heapOperands;
311        /**
312         * Current heap operand we're upto for the enumeration
313         */
314        private int curHeapOperand;
315        /**
316         * Implicit definitions from the operator
317         */
318        private final ArchitectureSpecificOpt.PhysicalDefUse.PDUEnumeration implicitDefs;
319        /**
320         * Defining instruction
321         */
322        private final Instruction instr;
323    
324        /**
325         * Construct/initialize object
326         *
327         * @param ir    Containing IR
328         * @param instr Instruction to get definitions for
329         */
330        public AllDefsEnum(IR ir, Instruction instr) {
331          this.instr = instr;
332          instructionOperands = instr.getDefs();
333          if (instr.operator().getNumberOfImplicitDefs() > 0) {
334            implicitDefs = ArchitectureSpecificOpt.PhysicalDefUse.enumerate(instr.operator().implicitDefs, ir);
335          } else {
336            implicitDefs = null;
337          }
338          if (ir.inSSAForm() && (instr.operator != PHI)) {
339            // Phi instructions store the heap SSA in the actual
340            // instruction
341            heapOperands = ir.HIRInfo.dictionary.getHeapDefs(instr);
342          } else {
343            heapOperands = null;
344          }
345        }
346    
347        /**
348         * Are there any more elements in the enumeration
349         */
350        @Override
351        public boolean hasMoreElements() {
352          return ((instructionOperands.hasMoreElements()) ||
353                  ((heapOperands != null) && (curHeapOperand < heapOperands.length)) ||
354                  ((implicitDefs != null) && (implicitDefs.hasMoreElements())));
355        }
356    
357        @Override
358        public Operand nextElement() {
359          if (instructionOperands.hasMoreElements()) {
360            return instructionOperands.nextElement();
361          } else {
362            if ((implicitDefs != null) && implicitDefs.hasMoreElements()) {
363              RegisterOperand rop = new RegisterOperand(implicitDefs.nextElement(), TypeReference.Int);
364              rop.instruction = instr;
365              return rop;
366            } else {
367              if (curHeapOperand >= heapOperands.length) {
368                fail("Regular and heap operands exhausted");
369              }
370              HeapOperand<?> result = heapOperands[curHeapOperand];
371              curHeapOperand++;
372              return result;
373            }
374          }
375        }
376      }
377    
378      /**
379       * This class implements an {@link Enumeration} of {@link Operand}. It used
380       * for holding the uses of a particular instruction and being used
381       * as an enumeration for iterating over. It differs from other
382       * enumerations of Operand as it iterates over both implicit
383       * and explicit operands.
384       * @see org.jikesrvm.compilers.opt.ssa.SSADictionary
385       */
386      public static final class AllUsesEnum implements Enumeration<Operand> {
387        /**
388         * Enumeration of non-heap operands defined by the instruction
389         */
390        private final Enumeration<Operand> instructionOperands;
391        /**
392         * Array of heap operands defined by the instruction
393         */
394        private final HeapOperand<?>[] heapOperands;
395        /**
396         * Current heap operand we're upto for the enumeration
397         */
398        private int curHeapOperand;
399        /**
400         * Implicit uses from the operator
401         */
402        private final PhysicalDefUse.PDUEnumeration implicitUses;
403        /**
404         * Defining instruction
405         */
406        private final Instruction instr;
407    
408        /**
409         * Construct/initialize object
410         *
411         * @param ir    Containing IR
412         * @param instr Instruction to get uses for
413         */
414        public AllUsesEnum(IR ir, Instruction instr) {
415          this.instr = instr;
416          instructionOperands = instr.getUses();
417          if (instr.operator().getNumberOfImplicitUses() > 0) {
418            implicitUses = PhysicalDefUse.enumerate(instr.operator().implicitUses, ir);
419          } else {
420            implicitUses = null;
421          }
422          if (ir.inSSAForm() && (instr.operator != PHI)) {
423            // Phi instructions store the heap SSA in the actual
424            // instruction
425            heapOperands = ir.HIRInfo.dictionary.getHeapUses(instr);
426          } else {
427            heapOperands = null;
428          }
429        }
430    
431        /**
432         * Are there any more elements in the enumeration
433         */
434        @Override
435        public boolean hasMoreElements() {
436          return ((instructionOperands.hasMoreElements()) ||
437                  ((heapOperands != null) && (curHeapOperand < heapOperands.length)) ||
438                  ((implicitUses != null) && (implicitUses.hasMoreElements())));
439        }
440    
441        @Override
442        public Operand nextElement() {
443          if (instructionOperands.hasMoreElements()) {
444            return instructionOperands.nextElement();
445          } else {
446            if ((implicitUses != null) && implicitUses.hasMoreElements()) {
447              RegisterOperand rop = new RegisterOperand(implicitUses.nextElement(), TypeReference.Int);
448              rop.instruction = instr;
449              return rop;
450            } else {
451              if (curHeapOperand >= heapOperands.length) {
452                fail("Regular and heap operands exhausted");
453              }
454              HeapOperand<?> result = heapOperands[curHeapOperand];
455              curHeapOperand++;
456              return result;
457            }
458          }
459        }
460      }
461    
462      @NoInline
463      private static void fail(String msg) throws java.util.NoSuchElementException {
464        throw new java.util.NoSuchElementException(msg);
465      }
466    }