Map<Variable,List<Variable>> simplificationMap = new HashMap<Variable,List<Variable>>();
Map<String,CodeVersion> versionMap = new HashMap<String,CodeVersion>();
ListIterator<Instr> instrs = s.getInstrs().listIterator();
while (instrs.hasNext()) {
Instr i = instrs.next();
Operation iop = i.operation;
if (iop.startsBasicBlock()) {
valueMap = new HashMap<Operand,Operand>();
simplificationMap = new HashMap<Variable,List<Variable>>();
versionMap = new HashMap<String, CodeVersion>();
}
// Simplify instruction and record mapping between target variable and simplified value
// System.out.println("BEFORE: " + i);
Operand val = i.simplifyAndGetResult(valueMap);
Variable res = i.getResult();
// System.out.println("For " + i + "; dst = " + res + "; val = " + val);
// System.out.println("AFTER: " + i);
if (val != null && res != null && res != val) {
recordSimplification(res, val, valueMap, simplificationMap);
if (val instanceof BreakResult) {
BreakResult br = (BreakResult)val;
i.markDead();
instrs.add(new CopyInstr(res, br._result));
instrs.add(new JumpInstr(br._jumpTarget));
}
}
// Optimize some core class method calls for constant values
else if (iop.isCall()) {
val = null;
CallInstr call = (CallInstr) i;
Operand r = call.getReceiver();
// SSS FIXME: r can be null for ruby/jruby internal call instructions!
// Cannot optimize them as of now.
if (r != null) {
// If 'r' is not a constant, it could actually be a compound value!
// Look in our value map to see if we have a simplified value for the receiver.
if (!r.isConstant()) {
Operand v = valueMap.get(r);
if (v != null)
r = v;
}
// Check if we can optimize this call based on the receiving method and receiver type
// Use the simplified receiver!
IRMethod rm = call.getTargetMethodWithReceiver(r);
if (rm != null) {
IRModule rc = rm.getDefiningIRModule();
if (rc != null) { // TODO: I am fairly sure I am wallpapering
if (rc.isCoreClass("Fixnum")) {
Operand[] args = call.getOperands();
if (args[2].isConstant()) {
addMethodGuard(rm, deoptLabel, versionMap, instrs);
val = ((Fixnum) r).computeValue(rm.getName(), (Constant) args[2]);
}
} else if (rc.isCoreClass("Float")) {
Operand[] args = call.getOperands();
if (args[2].isConstant()) {
addMethodGuard(rm, deoptLabel, versionMap, instrs);
val = ((Float) r).computeValue(rm.getName(), (Constant) args[2]);
}
} else if (rc.isCoreClass("Array")) {
Operand[] args = call.getOperands();
if (args[2] instanceof Fixnum && (rm.getName() == "[]")) {
addMethodGuard(rm, deoptLabel, versionMap, instrs);
val = ((Array) r).fetchCompileTimeArrayElement(((Fixnum) args[2]).value.intValue(), false);
}
}
}
// If we got a simplified value, mark the call dead and insert a copy in its place!
if (val != null) {
i.markDead();
instrs.add(new CopyInstr(res, val));
recordSimplification(res, val, valueMap, simplificationMap);
}
}
}
}
// Purge all entries in valueMap that have 'res' as their simplified value to take care of RAW scenarios (because we aren't in SSA form yet!)
if (res != null) {
List<Variable> simplifiedVars = simplificationMap.get(res);
if (simplifiedVars != null) {
for (Variable v: simplifiedVars)
valueMap.remove(v);
simplificationMap.remove(res);
}
}
// If the call has been optimized away in the previous step, it is no longer a hard boundary for opts!
if (iop.endsBasicBlock() || (iop.isCall() && !i.isDead())) {
valueMap = new HashMap<Operand,Operand>();
simplificationMap = new HashMap<Variable,List<Variable>>();
versionMap = new HashMap<String, CodeVersion>();
}
}