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.controlflow;
014    
015    import static org.jikesrvm.compilers.opt.driver.OptConstants.INSTRUMENTATION_BCI;
016    import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE_opcode;
017    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_BACKEDGE;
018    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_EPILOGUE;
019    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_PROLOGUE;
020    
021    import org.jikesrvm.VM;
022    import org.jikesrvm.compilers.opt.driver.CompilerPhase;
023    import org.jikesrvm.compilers.opt.inlining.InlineSequence;
024    import org.jikesrvm.compilers.opt.ir.BasicBlock;
025    import org.jikesrvm.compilers.opt.ir.BasicBlockEnumeration;
026    import org.jikesrvm.compilers.opt.ir.Empty;
027    import org.jikesrvm.compilers.opt.ir.IR;
028    import org.jikesrvm.compilers.opt.ir.Instruction;
029    import org.jikesrvm.compilers.opt.ir.Operator;
030    
031    /**
032     * This class inserts yield points in
033     *  1) a method's prologue
034     *  2) loop headers
035     *  3) (optionally) method exits (epilogue, athrow)
036     */
037    public class YieldPoints extends CompilerPhase {
038    
039      /**
040       * Return the name of this phase
041       * @return "Yield Point Insertion"
042       */
043      public final String getName() {
044        return "Yield Point Insertion";
045      }
046    
047      /**
048       * This phase contains no per-compilation instance fields.
049       */
050      public final CompilerPhase newExecution(IR ir) {
051        return this;
052      }
053    
054      /**
055       * Insert yield points in method prologues, loop heads, and method exits
056       *
057       * @param ir the governing IR
058       */
059      public final void perform(IR ir) {
060        if (!ir.method.isInterruptible()) {
061          return;   // don't insert yieldpoints in Uninterruptible code.
062        }
063    
064        // (1) Insert prologue yieldpoint unconditionally.
065        //     As part of prologue/epilogue insertion we'll remove
066        //     the yieldpoints in trival methods that otherwise wouldn't need
067        //     a stackframe.
068        prependYield(ir.cfg.entry(), YIELDPOINT_PROLOGUE, 0, ir.gc.inlineSequence);
069    
070        // (2) If using epilogue yieldpoints scan basic blocks, looking for returns or throws
071        if (VM.UseEpilogueYieldPoints) {
072          for (BasicBlockEnumeration e = ir.getBasicBlocks(); e.hasMoreElements();) {
073            BasicBlock block = e.next();
074            if (block.hasReturn() || block.hasAthrowInst()) {
075              prependYield(block, YIELDPOINT_EPILOGUE, INSTRUMENTATION_BCI, ir.gc.inlineSequence);
076            }
077          }
078        }
079    
080        // (3) Insert yieldpoints in loop heads based on the LST.
081        LSTGraph lst = ir.HIRInfo.loopStructureTree;
082        if (lst != null) {
083          for (java.util.Enumeration<LSTNode> e = lst.getRoot().getChildren(); e.hasMoreElements();) {
084            processLoopNest(e.nextElement());
085          }
086        }
087      }
088    
089      /**
090       * Process all loop heads in a loop nest by inserting a backedge yieldpoint in each of them.
091       */
092      private void processLoopNest(LSTNode n) {
093        for (java.util.Enumeration<LSTNode> e = n.getChildren(); e.hasMoreElements();) {
094          processLoopNest(e.nextElement());
095        }
096        Instruction dest = n.header.firstInstruction();
097        if (dest.position.getMethod().isInterruptible()) {
098          prependYield(n.header, YIELDPOINT_BACKEDGE, dest.bcIndex, dest.position);
099        }
100      }
101    
102      /**
103       * Add a YIELD instruction to the appropriate place for the basic
104       * block passed.
105       *
106       * @param bb the basic block
107       * @param yp the yieldpoint operator to insert
108       * @param bcIndex the bcIndex of the yieldpoint
109       * @param position the source position of the yieldpoint
110       */
111      private void prependYield(BasicBlock bb, Operator yp, int bcIndex, InlineSequence position) {
112        Instruction insertionPoint = null;
113    
114        if (bb.isEmpty()) {
115          insertionPoint = bb.lastInstruction();
116        } else {
117          insertionPoint = bb.firstRealInstruction();
118        }
119    
120        if (yp == YIELDPOINT_PROLOGUE) {
121          if (VM.VerifyAssertions) {
122            VM._assert((insertionPoint != null) && (insertionPoint.getOpcode() == IR_PROLOGUE_opcode));
123          }
124          // put it after the prologue
125          insertionPoint = insertionPoint.nextInstructionInCodeOrder();
126        } else if (VM.UseEpilogueYieldPoints && yp == YIELDPOINT_EPILOGUE) {
127          // epilogues go before the return or athrow (at end of block)
128          insertionPoint = bb.lastRealInstruction();
129        }
130    
131        Instruction s = Empty.create(yp);
132        insertionPoint.insertBefore(s);
133        s.position = position;
134        s.bcIndex = bcIndex;
135      }
136    }
137    
138    
139    
140