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