/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
/**
* This class holds information on scratch register usage, needed to
* adjust GC Maps.
*/
public final class OPT_ScratchMap {
private static final boolean DEBUG = false;
/**
* For each register, the set of intervals describing the register.
*/
private final HashMap<OPT_Register, ArrayList<Interval>> map = new HashMap<OPT_Register, ArrayList<Interval>>();
/**
* For each register, a pending (incomplete) interval under
* construction.
*/
private final HashMap<OPT_Register, Interval> pending = new HashMap<OPT_Register, Interval>();
/**
* For each GC Point s, a set of symbolic registers that are cached in
* dirty scratch registers before s.
*/
private final HashMap<OPT_Instruction, HashSet<OPT_Register>> dirtyMap =
new HashMap<OPT_Instruction, HashSet<OPT_Register>>();
/**
* Begin a new interval of scratch-ness for a symbolic register.
*
* @param r the symbolic register being moved into scratch
* @param scratch the physical register being used as a scratch
* @param begin the instruction before which the physical register is
* vacated.
*/
void beginSymbolicInterval(OPT_Register r, OPT_Register scratch, OPT_Instruction begin) {
if (DEBUG) {
System.out.println("beginSymbolicInterval " + r + " " + scratch + " " + begin.scratch);
}
SymbolicInterval i = new SymbolicInterval(r, scratch);
i.begin = begin;
ArrayList<Interval> v = findOrCreateIntervalSet(r);
v.add(i);
pending.put(r, i);
}
/**
* End an interval of scratch-ness for a symbolic register.
*
* @param r the symbolic register being moved into scratch
* @param end the instruction before which the scratch interval ends
*/
public void endSymbolicInterval(OPT_Register r, OPT_Instruction end) {
if (DEBUG) {
System.out.println("endSymbolicInterval " + r + " " + end.scratch);
}
SymbolicInterval i = (SymbolicInterval) pending.get(r);
i.end = end;
pending.remove(i);
}
/**
* Begin a new interval of scratch-ness for a physical register.
*
* @param r the physical register being used as a scratch
* @param begin the instruction before which the physical register is
* vacated.
*/
void beginScratchInterval(OPT_Register r, OPT_Instruction begin) {
if (DEBUG) {
System.out.println("beginScratchInterval " + r + " " + begin.scratch);
}
PhysicalInterval p = new PhysicalInterval(r);
p.begin = begin;
ArrayList<Interval> v = findOrCreateIntervalSet(r);
v.add(p);
pending.put(r, p);
}
/**
* End an interval of scratch-ness for a physical register.
*
* @param r the physical register being used as a scratch
* @param end the instruction before which the physical register is
* vacated.
*/
public void endScratchInterval(OPT_Register r, OPT_Instruction end) {
if (DEBUG) {
System.out.println("endScratchInterval " + r + " " + end.scratch);
}
PhysicalInterval p = (PhysicalInterval) pending.get(r);
p.end = end;
pending.remove(r);
}
/**
* Find or create the set of intervals corresponding to a register r.
*/
private ArrayList<Interval> findOrCreateIntervalSet(OPT_Register r) {
ArrayList<Interval> v = map.get(r);
if (v == null) {
v = new ArrayList<Interval>();
map.put(r, v);
}
return v;
}
/**
* If a physical register is being used as a scratch register at
* instruction n, return true; else, return false;
*/
boolean isScratch(OPT_Register r, int n) {
ArrayList<Interval> v = map.get(r);
if (v == null) return false;
for (final Interval interval : v) {
if (interval.contains(n)) return true;
}
return false;
}
/**
* If a symbolic register resides in a scratch register at an
* instruction numbered n, then return the scratch register. Else,
* return null.
*/
OPT_Register getScratch(OPT_Register r, int n) {
ArrayList<Interval> v = map.get(r);
if (v == null) return null;
for (Interval i : v) {
if (i.contains(n)) return i.scratch;
}
return null;
}
/**
* Is this map empty?
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* Note that at GC point s, the real value of register symb is cached in
* a dirty scratch register.
*/
public void markDirty(OPT_Instruction s, OPT_Register symb) {
HashSet<OPT_Register> set = dirtyMap.get(s);
if (set == null) {
set = new HashSet<OPT_Register>(3);
dirtyMap.put(s, set);
}
set.add(symb);
}
/**
* At GC point s, is the value of register r cached in a dirty scratch
* register?
*/
public boolean isDirty(OPT_Instruction s, OPT_Register r) {
HashSet<OPT_Register> set = dirtyMap.get(s);
if (set == null) {
return false;
} else {
return set.contains(r);
}
}
/**
* Return a String representation.
*/
public String toString() {
String result = "";
for (ArrayList<Interval> v : map.values()) {
for (Interval i : v) {
result += i + "\n";
}
}
return result;
}
/**
* Super class of physical and symbolic intervals
*/
private abstract static class Interval {
/**
* The instruction before which the scratch range begins.
*/
OPT_Instruction begin;
/**
* The instruction before which the scratch range ends.
*/
OPT_Instruction end;
/**
* The physical scratch register or register evicted.
*/
final OPT_Register scratch;
/**
* Initialize scratch register
*/
Interval(OPT_Register scratch) {
this.scratch = scratch;
}
/**
* Does this interval contain the instruction numbered n?
*/
final boolean contains(int n) {
return (begin.scratch <= n && end.scratch > n);
}
}
/**
* An object that represents an interval where a symbolic register
* resides in a scratch register.
* Note that this interval must not span a basic block.
*/
static final class SymbolicInterval extends Interval {
/**
* The symbolic register
*/
final OPT_Register symbolic;
SymbolicInterval(OPT_Register symbolic, OPT_Register scratch) {
super(scratch);
this.symbolic = symbolic;
}
/**
* Return a string representation, assuming the 'scratch' field of
* OPT_Instruction identifies an instruction.
*/
public String toString() {
return "SI: " + symbolic + " " + scratch + " [" + begin.scratch + "," + end.scratch + "]";
}
}
/**
* An object that represents an interval where a physical register's
* contents are evicted so that the physical register can be used as a
* scratch. Note that this interval must not span a basic block.
*/
static final class PhysicalInterval extends Interval {
PhysicalInterval(OPT_Register scratch) {
super(scratch);
}
/**
* Return a string representation, assuming the 'scratch' field of
* OPT_Instruction identifies an instruction.
*/
public String toString() {
return "PI: " + scratch + " [" + begin.scratch + "," + end.scratch + "]";
}
}
}