001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.regalloc;
014
015import java.util.HashSet;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.compilers.opt.OptOptions;
019import org.jikesrvm.compilers.opt.driver.CompilerPhase;
020import org.jikesrvm.compilers.opt.ir.GCIRMapElement;
021import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet;
022import org.jikesrvm.compilers.opt.ir.IR;
023import org.jikesrvm.compilers.opt.ir.Instruction;
024import org.jikesrvm.compilers.opt.ir.RegSpillListElement;
025import org.jikesrvm.compilers.opt.ir.Register;
026
027/**
028 * Update GC Maps again, to account for changes induced by spill code.
029 */
030final class UpdateGCMaps2 extends CompilerPhase {
031  /**
032   * Return this instance of this phase. This phase contains no
033   * per-compilation instance fields.
034   * @param ir not used
035   * @return this
036   */
037  @Override
038  public CompilerPhase newExecution(IR ir) {
039    return this;
040  }
041
042  @Override
043  public boolean shouldPerform(OptOptions options) {
044    return true;
045  }
046
047  @Override
048  public String getName() {
049    return "Update GCMaps 2";
050  }
051
052  @Override
053  public boolean printingEnabled(OptOptions options, boolean before) {
054    return false;
055  }
056
057  /**
058   *  @param ir the IR
059   */
060  @Override
061  public void perform(IR ir) {
062    GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
063    ScratchMap scratchMap = ir.stackManager.getScratchMap();
064    RegisterAllocatorState regAllocState = ir.MIRInfo.regAllocState;
065
066    if (LinearScan.GC_DEBUG) {
067      System.out.println("SCRATCH MAP:\n" + scratchMap);
068    }
069    if (scratchMap.isEmpty()) return;
070
071    // Walk over each instruction that has a GC point.
072    for (GCIRMapElement GCelement : ir.MIRInfo.gcIRMap) {
073      // new elements to add to the gc map
074      HashSet<RegSpillListElement> newElements = new HashSet<RegSpillListElement>();
075
076      Instruction GCinst = GCelement.getInstruction();
077
078      int dfn = regAllocState.getDFN(GCinst);
079
080      if (LinearScan.GC_DEBUG) {
081        VM.sysWrite("GCelement at " + dfn + " , " + GCelement);
082      }
083
084      // a set of elements to delete from the GC Map
085      HashSet<RegSpillListElement> toDelete = new HashSet<RegSpillListElement>(3);
086
087      // For each element in the GC Map ...
088      for (RegSpillListElement elem : GCelement.regSpillList()) {
089        if (LinearScan.GC_DEBUG) {
090          VM.sysWrite("Update " + elem + "\n");
091        }
092        if (elem.isSpill()) {
093          // check if the spilled value currently is cached in a scratch
094          // register
095          Register r = elem.getSymbolicReg();
096          Register scratch = scratchMap.getScratch(r, dfn);
097          if (scratch != null) {
098            if (LinearScan.GC_DEBUG) {
099              VM.sysWrite("cached in scratch register " + scratch + "\n");
100            }
101            // we will add a new element noting that the scratch register
102            // also must be including in the GC map
103            RegSpillListElement newElem = new RegSpillListElement(r);
104            newElem.setRealReg(scratch);
105            newElements.add(newElem);
106            // if the scratch register is dirty, then delete the spill
107            // location from the map, since it doesn't currently hold a
108            // valid value
109            if (scratchMap.isDirty(GCinst, r)) {
110              toDelete.add(elem);
111            }
112          }
113        } else {
114          // check if the physical register is currently spilled.
115          int n = elem.getRealRegNumber();
116          Register r = phys.get(n);
117          if (scratchMap.isScratch(r, dfn)) {
118            // The regalloc state knows where the physical register r is
119            // spilled.
120            if (LinearScan.GC_DEBUG) {
121              VM.sysWrite("CHANGE to spill location " + regAllocState.getSpill(r) + "\n");
122            }
123            elem.setSpill(regAllocState.getSpill(r));
124          }
125        }
126
127      }
128      // delete all obsolete elements
129      for (RegSpillListElement deadElem : toDelete) {
130        GCelement.deleteRegSpillElement(deadElem);
131      }
132
133      // add each new Element to the gc map
134      for (RegSpillListElement newElem : newElements) {
135        GCelement.addRegSpillElement(newElem);
136      }
137    }
138  }
139}