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.adaptive.recompilation.instrumentation;
014    
015    import java.lang.reflect.Constructor;
016    import java.util.ArrayList;
017    import java.util.Enumeration;
018    import java.util.HashMap;
019    import java.util.HashSet;
020    import java.util.Map;
021    import org.jikesrvm.VM;
022    import org.jikesrvm.adaptive.AosEntrypoints;
023    import org.jikesrvm.compilers.opt.DefUse;
024    import org.jikesrvm.compilers.opt.OptOptions;
025    import org.jikesrvm.compilers.opt.Simple;
026    import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
027    import org.jikesrvm.compilers.opt.driver.CompilerPhase;
028    import org.jikesrvm.compilers.opt.ir.Binary;
029    import org.jikesrvm.compilers.opt.ir.GetStatic;
030    import org.jikesrvm.compilers.opt.ir.Goto;
031    import org.jikesrvm.compilers.opt.ir.IfCmp;
032    import org.jikesrvm.compilers.opt.ir.InstrumentedCounter;
033    import org.jikesrvm.compilers.opt.ir.Load;
034    import org.jikesrvm.compilers.opt.ir.BasicBlock;
035    import org.jikesrvm.compilers.opt.ir.IR;
036    import org.jikesrvm.compilers.opt.ir.IRTools;
037    import org.jikesrvm.compilers.opt.ir.Instruction;
038    import org.jikesrvm.compilers.opt.ir.Operator;
039    import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC;
040    import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
041    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
042    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
043    import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
044    import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
045    import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE;
046    import static org.jikesrvm.compilers.opt.ir.Operators.LABEL;
047    import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC;
048    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_BACKEDGE;
049    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_PROLOGUE;
050    import org.jikesrvm.compilers.opt.ir.Register;
051    import org.jikesrvm.compilers.opt.ir.PutStatic;
052    import org.jikesrvm.compilers.opt.ir.Store;
053    import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
054    import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
055    import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
056    import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
057    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
058    import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
059    import org.jikesrvm.compilers.opt.ir.operand.Operand;
060    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
061    
062    /**
063     *  Transforms the method so that instrumentation is sampled, rather
064     *  than executed exhaustively.  Includes both the full-duplication
065     *  and no-duplication variations.  See Arnold-Ryder PLDI 2001, and
066     *  the section 4.1 of Arnold's PhD thesis.
067     *  <p>
068     *  NOTE: This implementation uses yieldpoints to denote where checks
069     *  should be placed (to transfer control into instrumented code).  It
070     *  is currently assumed that these are on method entries and
071     *  backedges.  When optimized yieldpoint placement exists either a)
072     *  it should be turned off when using this phase, or b) this phase
073     *  should detect its own check locations.
074     *  <p>
075     *  To avoid the complexity of duplicating exception handler maps,
076     *  exception handler blocks are split and a check at the top of the
077     *  handler.  Thus exceptions from both the checking and duplicated
078     *  code are handled by the same catch block, however the check at the
079     *  top of the catch block ensures that the hander code has the
080     *  opportunity to be sampled.
081     */
082    public final class InstrumentationSamplingFramework extends CompilerPhase {
083    
084      /**
085       * These are local copies of optimizing compiler debug options that can be
086       * set via the command line arguments.
087       */
088      private static boolean DEBUG = false;
089      private static boolean DEBUG2 = false;
090    
091      /**
092       * Temporary variables
093       */
094      private RegisterOperand cbsReg = null;
095    
096      /**
097       * Constructor for this compiler phase
098       */
099      private static final Constructor<CompilerPhase> constructor =
100          getCompilerPhaseConstructor(InstrumentationSamplingFramework.class);
101    
102      /**
103       * Get a constructor object for this compiler phase
104       * @return compiler phase constructor
105       */
106      @Override
107      public Constructor<CompilerPhase> getClassConstructor() {
108        return constructor;
109      }
110    
111      @Override
112      public boolean shouldPerform(OptOptions options) {
113        return options.ADAPTIVE_INSTRUMENTATION_SAMPLING;
114      }
115    
116      @Override
117      public String getName() { return "InstrumentationSamplingFramework"; }
118    
119      /**
120       * Perform this phase
121       *
122       * @param ir the governing IR
123       */
124      @Override
125      public void perform(IR ir) {
126    
127        DEBUG = ir.options.DEBUG_INSTRU_SAMPLING;
128        DEBUG2 = ir.options.DEBUG_INSTRU_SAMPLING_DETAIL;
129    
130        // Temp code for selective debugging.  Dump the whole IR if either DEBUG2 is set, or if a specific method name is specified.
131        if (DEBUG2 || (DEBUG && ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString()))) {
132          dumpIR(ir, "Before instrumentation sampling transformation");
133          dumpCFG(ir);
134        }
135    
136        // Perform the actual phase here.
137        if (ir.options.ADAPTIVE_NO_DUPLICATION) {
138          performVariationNoDuplication(ir);
139        } else {
140          performVariationFullDuplication(ir, this);
141        }
142    
143        // Dump method again after phase completes
144        if (DEBUG2 || (DEBUG && ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString()))) {
145          dumpIR(ir, "After instrumentation sampling transformation");
146          dumpCFG(ir);
147        }
148    
149        cleanUp(ir);
150    
151      }
152    
153    //  /**
154    //   * Initialization to perform before the transformation is applied
155    //   */
156    //  private static void initialize(IR ir) {
157    //
158    //  }
159    
160      //
161    
162      /**
163       * Initialization to perform after the transformation is applied
164       */
165      private void cleanUp(IR ir) {
166    
167        // Clean up the ir with simple optimizations
168        Simple simple = new Simple(-1, false, false, false, false);
169        simple.perform(ir);
170    
171        // Perform branch optimizations (level 0 is passed because if we
172        // always want to call it if we've used the sampling framework).
173        BranchOptimizations branchOpt = new BranchOptimizations(0, true, true);
174        branchOpt.perform(ir);
175    
176        // Clear the static variables
177        cbsReg = null;
178    
179        //
180        //    RegisterInfo.computeRegisterList(ir);
181        DefUse.recomputeSpansBasicBlock(ir);
182        DefUse.recomputeSSA(ir);
183      }
184    
185      /**
186       * Perform the full duplication algorithm
187       *
188       * @param ir the governing IR
189       */
190      private void performVariationFullDuplication(IR ir, CompilerPhase phaseObject) {
191    
192        // Initialize
193    
194        // Used to store mapping from original to duplicated blocks
195        HashMap<BasicBlock, BasicBlock> origToDupMap = new HashMap<BasicBlock, BasicBlock>();
196        // Used to remember all exception handler blocks
197        HashSet<BasicBlock> exceptionHandlerBlocks = new HashSet<BasicBlock>();
198        // The register containing the counter value to check
199        cbsReg = ir.regpool.makeTempInt();
200    
201        // 1) Make a copy of all basic blocks
202        duplicateCode(ir, origToDupMap, exceptionHandlerBlocks);
203    
204        // 2) Insert counter-based sampling checks  (record blocks with YP's)
205        insertCBSChecks(ir, origToDupMap, exceptionHandlerBlocks);
206    
207        // 3) Fix control flow edges in duplicated code
208        adjustPointersInDuplicatedCode(ir, origToDupMap);
209    
210        // 4) Remove instrumentation from checking code
211        removeInstrumentationFromOrig(ir, origToDupMap);
212    
213        if (ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
214          ir.verify("End of Framework");
215        }
216    
217      }
218    
219      /**
220       * Make a duplicate of all basic blocks down at the bottom of the
221       * code order.  For now, this is done in a slightly ackward way.
222       * After duplication, the control flow within the duplicated code is
223       * not complete because each block immediately transfers you back to
224       * the original code.  This gets fixed in
225       * adjustPointersInDuplicatedCode
226       *
227       * @param ir the governing IR */
228      private void duplicateCode(IR ir, HashMap<BasicBlock, BasicBlock> origToDupMap,
229                                 HashSet<BasicBlock> exceptionHandlerBlocks) {
230    
231        if (DEBUG) VM.sysWrite("In duplicate code\n");
232    
233        // Iterate through all blocks and duplicate them.  While
234        // iterating, loop until you see the block that was the *original*
235        // last block.  (Need to do it this way because we're adding
236        // blocks to the end as we loop.)
237        BasicBlock origLastBlock = ir.cfg.lastInCodeOrder();
238        boolean done = false;
239        BasicBlock curBlock = ir.cfg.firstInCodeOrder();
240        while (!done && curBlock != null) {
241          if (curBlock == origLastBlock) {
242            // Stop after this iteration
243            done = true;
244          }
245    
246          // Don't duplicate the exit node
247          if (curBlock == ir.cfg.exit()) {
248            // Next block
249            curBlock = curBlock.nextBasicBlockInCodeOrder();
250            continue;
251          }
252    
253          // Check if the block needs to be split for later insertion of
254          // a check.  We split the entry basic block (first basic block
255          // in the method) to insert the method-entry check, and also
256          // exception handler blocks to simplify handling
257          if (curBlock == ir.cfg.entry() || curBlock.isExceptionHandlerBasicBlock()) {
258    
259            Instruction splitInstr = null;
260    
261            if (curBlock == ir.cfg.entry()) {
262              splitInstr = getFirstInstWithOperator(IR_PROLOGUE, curBlock);
263            } else {
264              splitInstr = getFirstInstWithOperator(LABEL, curBlock);
265            }
266    
267            // Split entry node so the split instr isn't duplicated, but rest
268            // of block is.
269            BasicBlock blockTail = curBlock.splitNodeWithLinksAt(splitInstr, ir);
270            curBlock.recomputeNormalOut(ir);
271    
272            if (curBlock.isExceptionHandlerBasicBlock()) {
273              // Remember that the tail of the block we just split is an
274              // exception handler and we want to add a check here
275              exceptionHandlerBlocks.add(blockTail);
276            }
277    
278            // proceed with the duplication using the second half of the split block.
279            curBlock = blockTail;
280    
281            // Is this necessary?   TODO:  see if it can be removed.
282            DefUse.recomputeSpansBasicBlock(ir);
283          }
284    
285          // Copy the basic block
286          BasicBlock dup = myCopyWithoutLinks(curBlock, ir);
287          dup.setInfrequent();  // duplicated code is known to be infrequent.
288    
289          if (DEBUG2) {
290            VM.sysWrite("Copying bb: " + curBlock + " to be " + dup + "\n");
291          }
292    
293          ir.cfg.addLastInCodeOrder(dup);
294    
295          // Attach a goto to the duplicated code block, so that it
296          // doesn't fall through within the duplicated code, and jumps
297          // back to the checking code.  This is a bit of a convoluted way
298          // of doing things and could be cleaned up.  It was done
299          // originally done to make the remaining passes simpler.
300          BasicBlock fallthrough = curBlock.getFallThroughBlock();
301          if (fallthrough != null) {
302    
303            Instruction g = Goto.create(GOTO, fallthrough.makeJumpTarget());
304            dup.appendInstruction(g);
305          }
306    
307          dup.recomputeNormalOut(ir);
308    
309          origToDupMap.put(curBlock, dup); // Remember that basic block "dup"
310    
311          // Next block
312          curBlock = curBlock.nextBasicBlockInCodeOrder();
313        }
314      }
315    
316      /**
317       * In the checking code, insert CBS checks at each yieldpoint, to
318       * transfer code into the duplicated (instrumented) code.
319       * For now, checks are inserted at all yieldpoints (See comment at
320       * top of file).
321       *
322       * @param ir the governing IR
323       */
324      private void insertCBSChecks(IR ir, HashMap<BasicBlock, BasicBlock> origToDupMap,
325                                   HashSet<BasicBlock> exceptionHandlerBlocks) {
326    
327        // Iterate through the basic blocks in the original code
328        for (Map.Entry<BasicBlock, BasicBlock> entry : origToDupMap.entrySet()) {
329          BasicBlock bb = entry.getKey();
330          BasicBlock dup = entry.getValue();
331    
332          if (dup == null) {
333            // Getting here means that for some reason the block was not duplicated.
334            if (DEBUG) {
335              VM.sysWrite("Debug: block " + bb + " was not duplicated\n");
336            }
337            continue;
338          }
339    
340          // If you have a yieldpoint, or if you are the predecessor of a
341          // split exception handler when duplicating code) then insert a
342          // check
343    
344          if (getFirstInstWithYieldPoint(bb) != null ||   // contains yieldpoint
345              exceptionHandlerBlocks.contains(bb)) { // is exception handler
346    
347            BasicBlock checkBB = null;
348            BasicBlock prev = bb.prevBasicBlockInCodeOrder();
349            // Entry has been split, so any node containing a yieldpoint
350            // should not be first
351            if (VM.VerifyAssertions) {
352              VM._assert(prev != null);
353            }
354    
355            // Make a new BB that contains the check itself (it needs to
356            // be a basic block because the duplicated code branches back
357            // to it).
358            checkBB = new BasicBlock(-1, null, ir.cfg);
359    
360            // Break the code to insert the check logic
361            ir.cfg.breakCodeOrder(prev, bb);
362            ir.cfg.linkInCodeOrder(prev, checkBB);
363            ir.cfg.linkInCodeOrder(checkBB, bb);
364            if (DEBUG) {
365              VM.sysWrite("Creating check " + checkBB + " to preceed " + bb + " \n");
366            }
367    
368            // Step 2, Make all of bb's predecessors point to the check instead
369            for (Enumeration<BasicBlock> preds = bb.getIn(); preds.hasMoreElements();) {
370              BasicBlock pred = preds.nextElement();
371              pred.redirectOuts(bb, checkBB, ir);
372            }
373    
374            // Insert the check logic
375            createCheck(checkBB, bb, dup, false, ir);
376    
377          }
378        }
379      }
380    
381      /**
382       * Append a check to a basic block, and make it jump to the right places.
383       *
384       * @param checkBB The block to append the CBS check to.
385       * @param noInstBB The basic block to jump to if the CBS check fails
386       * @param instBB The basicBlock to jump to if the CBS check succeeds
387       * @param fallthroughToInstBB Should checkBB fallthrough to instBB
388       *                            (otherwise it must fallthrough to noInstBB)
389       */
390      private void createCheck(BasicBlock checkBB, BasicBlock noInstBB, BasicBlock instBB,
391                               boolean fallthroughToInstBB, IR ir) {
392    
393        appendLoad(checkBB, ir);
394    
395        // Depending on where you fallthrough, set the condition correctly
396        ConditionOperand cond = null;
397        BranchOperand target = null;
398        BranchProfileOperand profileOperand = null;
399        if (fallthroughToInstBB) {
400          // The instrumented basic block is the fallthrough of checkBB,
401          // so make the branch jump to the non-instrumented block.
402          cond = ConditionOperand.GREATER();
403          target = noInstBB.makeJumpTarget();
404          profileOperand = new BranchProfileOperand(1.0f); // Taken frequently
405        } else {
406          // The non-instrumented basic block is the fallthrough of checkBB,
407          // so make the branch jump to the instrumented block.
408          cond = ConditionOperand.LESS_EQUAL();
409          target = instBB.makeJumpTarget();
410          profileOperand = new BranchProfileOperand(0.0f); // Taken infrequently
411        }
412        RegisterOperand guard = ir.regpool.makeTempValidation();
413        checkBB.appendInstruction(IfCmp.create(INT_IFCMP,
414                                               guard,
415                                               cbsReg.copyRO(),
416                                               new IntConstantOperand(0),
417                                               cond,
418                                               target,
419                                               profileOperand));
420        checkBB.recomputeNormalOut(ir);
421    
422        // Insert the decrement and store in the block that is the
423        // successor of the check
424        prependStore(noInstBB, ir);
425        prependDecrement(noInstBB, ir);
426    
427        // Insert a counter reset in the duplicated block.
428        prependCounterReset(instBB, ir);
429    
430      }
431    
432      /**
433       * Append a load of the global counter to the given basic block.
434       *
435       * WARNING: Tested for LIR only!
436       *
437       * @param bb The block to append the load to
438       * @param ir The IR */
439      private void appendLoad(BasicBlock bb, IR ir) {
440    
441        if (DEBUG) VM.sysWrite("Adding load to " + bb + "\n");
442        Instruction load = null;
443        if (ir.options.ADAPTIVE_PROCESSOR_SPECIFIC_COUNTER) {
444          // Use one CBS counter per processor (better for multi threaded apps)
445    
446          if (ir.IRStage == IR.HIR) {
447            // NOT IMPLEMENTED
448          } else {
449            // Phase is being used in LIR
450            // Insert the load instruction.
451            load =
452                Load.create(INT_LOAD,
453                            cbsReg.copyRO(),
454                            ir.regpool.makeTROp(),
455                            IRTools.AC(AosEntrypoints.threadCBSField.getOffset()),
456                            new LocationOperand(AosEntrypoints.threadCBSField));
457    
458            bb.appendInstruction(load);
459          }
460        } else {
461          // Use global counter
462          if (ir.IRStage == IR.HIR) {
463            Operand offsetOp = new AddressConstantOperand(AosEntrypoints.globalCBSField.getOffset());
464            load =
465                GetStatic.create(GETSTATIC,
466                                 cbsReg.copyRO(),
467                                 offsetOp,
468                                 new LocationOperand(AosEntrypoints.globalCBSField));
469            bb.appendInstruction(load);
470          } else {
471            // LIR
472            Instruction dummy = Load.create(INT_LOAD, null, null, null, null);
473    
474            bb.appendInstruction(dummy);
475            load =
476                Load.create(INT_LOAD,
477                            cbsReg.copyRO(),
478                            ir.regpool.makeJTOCOp(ir, dummy),
479                            IRTools.AC(AosEntrypoints.globalCBSField.getOffset()),
480                            new LocationOperand(AosEntrypoints.globalCBSField));
481    
482            dummy.insertBefore(load);
483            dummy.remove();
484          }
485        }
486      }
487    
488      /**
489       * Append a store of the global counter to the given basic block.
490       *
491       * WARNING: Tested in LIR only!
492       *
493       * @param bb The block to append the load to
494       * @param ir The IR */
495      private void prependStore(BasicBlock bb, IR ir) {
496    
497        if (DEBUG) VM.sysWrite("Adding store to " + bb + "\n");
498        Instruction store = null;
499        if (ir.options.ADAPTIVE_PROCESSOR_SPECIFIC_COUNTER) {
500          store =
501              Store.create(INT_STORE,
502                           cbsReg.copyRO(),
503                           ir.regpool.makeTROp(),
504                           IRTools.AC(AosEntrypoints.threadCBSField.getOffset()),
505                           new LocationOperand(AosEntrypoints.threadCBSField));
506    
507          bb.prependInstruction(store);
508        } else {
509          if (ir.IRStage == IR.HIR) {
510            store =
511                PutStatic.create(PUTSTATIC,
512                                 cbsReg.copyRO(),
513                                 new AddressConstantOperand(AosEntrypoints.globalCBSField.getOffset()),
514                                 new LocationOperand(AosEntrypoints.globalCBSField));
515    
516            bb.prependInstruction(store);
517          } else {
518            Instruction dummy = Load.create(INT_LOAD, null, null, null, null);
519    
520            bb.prependInstruction(dummy);
521            store =
522                Store.create(INT_STORE,
523                             cbsReg.copyRO(),
524                             ir.regpool.makeJTOCOp(ir, dummy),
525                             IRTools.AC(AosEntrypoints.globalCBSField.getOffset()),
526                             new LocationOperand(AosEntrypoints.globalCBSField));
527    
528            dummy.insertBefore(store);
529            dummy.remove();
530          }
531        }
532      }
533    
534      /**
535       * Append a decrement of the global counter to the given basic block.
536       *
537       * Tested in LIR only!
538       *
539       * @param bb The block to append the load to
540       * @param ir The IR
541       */
542      private void prependDecrement(BasicBlock bb, IR ir) {
543        if (DEBUG) VM.sysWrite("Adding Increment to " + bb + "\n");
544    
545        RegisterOperand use = cbsReg.copyRO();
546        RegisterOperand def = use.copyU2D();
547        Instruction inc = Binary.create(INT_ADD, def, use, IRTools.IC(-1));
548        bb.prependInstruction(inc);
549      }
550    
551      /**
552       * Prepend the code to reset the global counter to the given basic
553       * block.
554       *
555       * Warning:  Tested in LIR only!
556       *
557       * @param bb The block to append the load to
558       * @param ir The IR */
559      private void prependCounterReset(BasicBlock bb, IR ir) {
560        Instruction load = null;
561        Instruction store = null;
562    
563        if (ir.IRStage == IR.HIR) {
564          // Not tested
565          Operand offsetOp = new AddressConstantOperand(AosEntrypoints.cbsResetValueField.getOffset());
566          load =
567              GetStatic.create(GETSTATIC,
568                               cbsReg.copyRO(),
569                               offsetOp,
570                               new LocationOperand(AosEntrypoints.cbsResetValueField));
571          store =
572              PutStatic.create(PUTSTATIC,
573                               cbsReg.copyRO(),
574                               new AddressConstantOperand(AosEntrypoints.globalCBSField.getOffset()),
575                               new LocationOperand(AosEntrypoints.globalCBSField));
576          bb.prependInstruction(store);
577          bb.prependInstruction(load);
578        } else {
579          // LIR
580          Instruction dummy = Load.create(INT_LOAD, null, null, null, null);
581          bb.prependInstruction(dummy);
582          // Load the reset value
583          load =
584              Load.create(INT_LOAD,
585                          cbsReg.copyRO(),
586                          ir.regpool.makeJTOCOp(ir, dummy),
587                          IRTools.AC(AosEntrypoints.cbsResetValueField.getOffset()),
588                          new LocationOperand(AosEntrypoints.cbsResetValueField));
589    
590          dummy.insertBefore(load);
591    
592          // Store it in the counter register
593          if (ir.options.ADAPTIVE_PROCESSOR_SPECIFIC_COUNTER) {
594            store =
595                Store.create(INT_STORE,
596                             cbsReg.copyRO(),
597                             ir.regpool.makeTROp(),
598                             IRTools.AC(AosEntrypoints.threadCBSField.getOffset()),
599                             new LocationOperand(AosEntrypoints.threadCBSField));
600          } else {
601            // Use global counter
602            store =
603                Store.create(INT_STORE,
604                             cbsReg.copyRO(),
605                             ir.regpool.makeJTOCOp(ir, dummy),
606                             IRTools.AC(AosEntrypoints.globalCBSField.getOffset()),
607                             new LocationOperand(AosEntrypoints.globalCBSField));
608          }
609          dummy.insertBefore(store);
610          dummy.remove();
611        }
612    
613      }
614    
615      /**
616       *  Go through all instructions and find the first with the given
617       *  operator.
618       *
619       * @param operator The operator to look for
620       * @param bb The basic block in which to look
621       * @return The first instruction in bb that has operator operator.  */
622      private static Instruction getFirstInstWithOperator(Operator operator, BasicBlock bb) {
623        for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
624          Instruction i = ie.nextElement();
625    
626          if (i.operator() == operator) {
627            return i;
628          }
629        }
630        return null;
631      }
632    
633      /**
634       *  Go through all instructions and find one that is a yield point
635       *
636       * @param bb The basic block in which to look
637       * @return The first instruction in bb that has a yield point
638       */
639      public static Instruction getFirstInstWithYieldPoint(BasicBlock bb) {
640        for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
641          Instruction i = ie.nextElement();
642    
643          if (isYieldpoint(i)) {
644            return i;
645          }
646        }
647        return null;
648      }
649    
650      /**
651       *  Is the given instruction a yieldpoint?
652       *
653       *  For now we ignore epilogue yieldpoints since we are only concerned with
654       *  method entries and backedges.
655       */
656      public static boolean isYieldpoint(Instruction i) {
657        return i.operator() == YIELDPOINT_PROLOGUE ||
658               // Skip epilogue yieldpoints.   No checks needed for them
659               //        i.operator() == YIELDPOINT_EPILOGUE ||
660               i.operator() == YIELDPOINT_BACKEDGE;
661    
662      }
663    
664      /**
665       * Go through all blocks in duplicated code and adjust the edges as
666       * follows:
667       * <ol>
668       *   <li>All edges (in duplicated code) that go into a block with a
669       * yieldpoint must jump to back to the original code.  This is
670       * actually already satisfied because we appended goto's to all
671       * duplicated bb's (the goto's go back to orig code)
672       *   <li>All edges that do NOT go into a yieldpoint block must stay
673       * (either fallthrough or jump to a block in) in the duplicated
674       * code.
675       * </ol>
676       *
677       * @param ir the governing IR */
678      private static void adjustPointersInDuplicatedCode(IR ir, HashMap<BasicBlock, BasicBlock> origToDupMap) {
679    
680        // Iterate over the original version of all duplicate blocks
681        for (BasicBlock dupBlock : origToDupMap.values()) {
682    
683          // Look at the successors of duplicated Block.
684          for (Enumeration<BasicBlock> out = dupBlock.getNormalOut(); out.hasMoreElements();) {
685            BasicBlock origSucc = out.nextElement();
686    
687            BasicBlock dupSucc = origToDupMap.get(origSucc);
688    
689            // If the successor is not in the duplicated code, then
690            // redirect it to stay in the duplicated code. (dupSucc !=
691            // null implies that origSucc has a corresponding duplicated
692            // block, and thus origSucc is in the checking code.
693    
694            if (dupSucc != null) {
695    
696              dupBlock.redirectOuts(origSucc, dupSucc, ir);
697              if (DEBUG) {
698                VM.sysWrite("Source: " + dupBlock + "\n");
699                VM.sysWrite("============= FROM " + origSucc + " =============\n");
700                //origSucc.printExtended();
701                VM.sysWrite("============= TO " + dupSucc + "=============\n");
702                //dupSucc.printExtended();
703              }
704            } else {
705              if (DEBUG) {
706                VM.sysWrite("Not adjusting pointer from " + dupBlock + " to " + origSucc + " because dupSucc is null\n");
707              }
708            }
709          }
710    
711        }
712      }
713    
714      /**
715       * Remove instrumentation from the original version of all duplicated
716       * basic blocks.<p>
717       *
718       * The yieldpoints can also be removed from either the original or
719       * the duplicated code.  If you remove them from the original, it
720       * will make it run faster (since it is executed more than the
721       * duplicated) however that means that you can't turn off the
722       * instrumentation or you could infinitely loop without executing
723       * yieldpoints!
724       *
725       * @param ir the governing IR */
726      private static void removeInstrumentationFromOrig(IR ir, HashMap<BasicBlock, BasicBlock> origToDupMap) {
727        // Iterate over the original version of all duplicate blocks
728    
729        for (BasicBlock origBlock : origToDupMap.keySet()) {
730    
731          // Remove all instrumentation instructions.  They already have
732          // been transfered to the duplicated code.
733          for (Enumeration<Instruction> ie = origBlock.forwardInstrEnumerator(); ie.hasMoreElements();) {
734            Instruction i = ie.nextElement();
735            if (isInstrumentationInstruction(i) || (isYieldpoint(i) && ir.options.ADAPTIVE_REMOVE_YP_FROM_CHECKING)) {
736    
737              if (DEBUG) VM.sysWrite("Removing " + i + "\n");
738              i.remove();
739            }
740          }
741        }
742      }
743    
744      /**
745       * The same as BasicBlock.copyWithoutLinks except that it
746       * renames all temp variables that are never used outside the basic
747       * block.  This 1) helps eliminate the artificially large live
748       * ranges that might have been created (assuming the reg allocator
749       * isn't too smart) and 2) it prevents BURS from crashing.
750       * <p>
751       * PRECONDITION:  the spansBasicBlock bit must be correct by calling
752       *                DefUse.recomputeSpansBasicBlock(IR);
753       */
754      private static BasicBlock myCopyWithoutLinks(BasicBlock bb, IR ir) {
755    
756        BasicBlock newBlock = bb.copyWithoutLinks(ir);
757    
758        // Without this, there were sanity errors at one point.
759        updateTemps(newBlock, ir);
760    
761        return newBlock;
762      }
763    
764      /**
765       * Given an basic block, rename all of the temporary registers that are local to the block.
766       */
767      private static void updateTemps(BasicBlock bb, IR ir) {
768    
769        // Need to clear the scratch objects before we start using them
770        clearScratchObjects(bb, ir);
771    
772        // For each instruction in the block
773        for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
774          Instruction inst = ie.nextElement();
775    
776          // Look at each register operand
777          int numOperands = inst.getNumberOfOperands();
778          for (int i = 0; i < numOperands; i++) {
779            Operand op = inst.getOperand(i);
780            if (op instanceof RegisterOperand) {
781              RegisterOperand ro = (RegisterOperand) op;
782              if (ro.getRegister().isTemp() && !ro.getRegister().spansBasicBlock()) {
783                // This register does not span multiple basic blocks, so
784                // replace it with a temp.
785                RegisterOperand newReg = getOrCreateDupReg(ro, ir);
786                if (DEBUG2) {
787                  VM.sysWrite("Was " + ro + " and now it's " + newReg + "\n");
788                }
789                inst.putOperand(i, newReg);
790              }
791            }
792          }
793        }
794    
795        // Clear them afterward also, otherwise register allocation fails.
796        // (TODO: Shouldn't they just be cleared before use in register
797        // allocation?)
798        clearScratchObjects(bb, ir);
799      }
800    
801      /**
802       *  Go through all statements in the basic block and clear the
803       *  scratch objects.
804       */
805      private static void clearScratchObjects(BasicBlock bb, IR ir) {
806        // For each instruction in the block
807        for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
808          Instruction inst = ie.nextElement();
809    
810          // Look at each register operand
811          int numOperands = inst.getNumberOfOperands();
812          for (int i = 0; i < numOperands; i++) {
813            Operand op = inst.getOperand(i);
814            if (op instanceof RegisterOperand) {
815              RegisterOperand ro = (RegisterOperand) op;
816              if (ro.getRegister().isTemp() && !ro.getRegister().spansBasicBlock()) {
817    
818                // This register does not span multiple basic blocks.  It
819                // will be touched by the register duplication, so clear
820                // its scratch reg.
821                ro.getRegister().scratchObject = null;
822              }
823            }
824          }
825        }
826    
827      }
828    
829      /**
830       * The given register a) does not span multiple basic block, and b)
831       * is used in a basic block that is being duplicated.   It is
832       * therefore safe to replace all occurrences of the register with a
833       * new register.  This method returns the duplicated
834       * register that is associated with the given register.  If a
835       * duplicated register does not exist, it is created and recorded.
836       */
837      private static RegisterOperand getOrCreateDupReg(RegisterOperand ro, IR ir) {
838    
839        // Check if the register associated with this regOperand already
840        // has a paralles operand
841        if (ro.getRegister().scratchObject == null) {
842          // If no dup register exists, make a new one and remember it.
843          RegisterOperand dupRegOp = ir.regpool.makeTemp(ro.getType());
844          ro.getRegister().scratchObject = dupRegOp.getRegister();
845        }
846        return new RegisterOperand((Register) ro.getRegister().scratchObject, ro.getType());
847      }
848    
849      /**
850       * Perform the NoDuplication version of the framework (see
851       * Arnold-Ryder PLDI 2001).  Instrumentation operations are wrapped
852       * in a conditional, but no code duplication is performed.
853       */
854      private void performVariationNoDuplication(IR ir) {
855        // The register containing the counter value to check
856        cbsReg = ir.regpool.makeTempInt();
857    
858        ArrayList<Instruction> instrumentationOperations = new ArrayList<Instruction>();
859        for (Enumeration<BasicBlock> allBB = ir.getBasicBlocks(); allBB.hasMoreElements();) {
860          BasicBlock bb = allBB.nextElement();
861    
862          for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
863            Instruction i = ie.nextElement();
864    
865            // If it's an instrumentation operation, remember the instruction
866            if (isInstrumentationInstruction(i)) {
867              instrumentationOperations.add(i);
868            }
869          }
870        }
871    
872        // for each instrumentation operation.
873        for (Instruction i : instrumentationOperations) {
874          BasicBlock bb = i.getBasicBlock();
875          conditionalizeInstrumentationOperation(ir, i, bb);
876        }
877      }
878    
879      /**
880       * Take an instrumentation operation (an instruction) and guard it
881       * with a counter-based check.
882       * <ol>
883       *   <li>split the basic block before and after the i
884       *    to get A -> B -> C
885       *   <li>Add check to A, making it go to B if it succeeds, otherwise C
886       * </ol>
887       */
888      private void conditionalizeInstrumentationOperation(IR ir, Instruction i, BasicBlock bb) {
889    
890        // Create bb after instrumentation ('C', in comment above)
891        BasicBlock C = bb.splitNodeWithLinksAt(i, ir);
892        bb.recomputeNormalOut(ir);
893    
894        // Create bb before instrumentation ('A', in comment above)
895        Instruction prev = i.prevInstructionInCodeOrder();
896    
897        BasicBlock B = null;
898        try {
899          B = bb.splitNodeWithLinksAt(prev, ir);
900        } catch (RuntimeException e) {
901          VM.sysWrite("Bombed when I: " + i + " prev: " + prev + "\n");
902          bb.printExtended();
903          throw e;
904        }
905    
906        bb.recomputeNormalOut(ir);
907    
908        BasicBlock A = bb;
909    
910        // Now, add check to A, that jumps to C
911        createCheck(A, C, B, true, ir);
912      }
913    
914      /**
915       * How to determine whether a given instruction is an
916       * "instrumentation instruction".  In other words, it should be
917       * executed only when a sample is being taken.
918       */
919      private static boolean isInstrumentationInstruction(Instruction i) {
920    
921        //    if (i.bcIndex == INSTRUMENTATION_BCI &&
922        // (Call.conforms(i) ||
923        // if (InstrumentedCounter.conforms(i)))
924    
925        return InstrumentedCounter.conforms(i);
926      }
927    
928      /**
929       * Temp debugging code
930       */
931      public static void dumpCFG(IR ir) {
932    
933        for (Enumeration<BasicBlock> allBB = ir.getBasicBlocks(); allBB.hasMoreElements();) {
934          BasicBlock curBB = allBB.nextElement();
935          curBB.printExtended();
936        }
937      }
938    }
939    
940    
941