public void applyTransferFunction(Instr i) { // Rescue node, if any boolean scopeBindingHasEscaped = problem.getScope().bindingHasEscaped(); Variable dst = null; boolean dirtied = false; boolean hitDFBarrier = false; if (i instanceof ResultInstr) { dst = ((ResultInstr) i).getResult(); } if (i instanceof CopyInstr) { // Copies are easy Operand src = ((CopyInstr) i).getSource(); Class srcType = getOperandType(tmpState, src); setOperandType(tmpState, dst, srcType); // If we have an unboxed type for 'src', we can leave this unboxed. // // FIXME: However, if 'src' is a constant, this could unnecessarily // leave 'src' unboxed and lead to a boxing instruction further down // at the use site of 'dst'. This indicates that leaving this unboxed // should ideally be done 'on-demand'. This indicates that this could // be a backward-flow algo OR that this algo should be run on a // dataflow graph / SSA graph. if (srcType == Float.class) { dirtied = true; } } else if (i instanceof CallBase) { // Process calls specially -- these are what we want to optimize! CallBase c = (CallBase) i; Operand o = c.getClosureArg(null); if (o == null) { MethAddr m = c.getMethodAddr(); Operand r = c.getReceiver(); Operand[] args = c.getCallArgs(); if (args.length == 1 && m.resemblesALUOp()) { Operand a = args[0]; Class receiverType = getOperandType(tmpState, r); Class argType = getOperandType(tmpState, a); // Optimistically assume that call is an ALU op if (receiverType == Float.class || (receiverType == Fixnum.class && argType == Float.class)) { setOperandType(tmpState, dst, Float.class); // If 'r' and 'a' are not already in unboxed forms at this point, // they will get unboxed after this, because we want to opt. this call if (r instanceof Variable) { tmpState.unboxedVars.add((Variable) r); } if (a instanceof Variable) { tmpState.unboxedVars.add((Variable) a); } dirtied = true; } else { if (receiverType == Fixnum.class && argType == Fixnum.class) { setOperandType(tmpState, dst, Fixnum.class); } else { setOperandType(tmpState, dst, Object.class); } if (c.targetRequiresCallersBinding()) { hitDFBarrier = true; } } } else { setOperandType(tmpState, dst, Object.class); } } else { if (o instanceof WrappedIRClosure) { // Fetch the nested unboxing-analysis problem, creating one if necessary IRClosure cl = ((WrappedIRClosure) o).getClosure(); UnboxableOpsAnalysisProblem subProblem = (UnboxableOpsAnalysisProblem) cl.getDataFlowSolution(DataFlowConstants.UNBOXING); if (subProblem == null) { subProblem = new UnboxableOpsAnalysisProblem(); subProblem.setup(cl); cl.setDataFlowSolution(DataFlowConstants.UNBOXING, subProblem); } UnboxableOpsAnalysisNode exitNode = (UnboxableOpsAnalysisNode) subProblem.getExitNode(); UnboxableOpsAnalysisNode entryNode = (UnboxableOpsAnalysisNode) subProblem.getEntryNode(); // Init it to MEET(state-on-entry, state-on-exit). // The meet is required to account for participation of the closure in a loop. // Ex: f = 0.0; n.times { f += 10; } entryNode.inState = new UnboxState(); for (Variable v : tmpState.types.keySet()) { if (v instanceof LocalVariable) { entryNode.inState.types.put(v, tmpState.types.get(v)); } } entryNode.inState.computeMEET(exitNode.outState); // Compute solution subProblem.compute_MOP_Solution(); // Update types to MEET(new-state-on-exit, current-state) tmpState.computeMEETForTypes(exitNode.outState, true); // As for unboxed var state, since binding can escape in // arbitrary ways in the general case, assume the worst for now. // If we are guaranteed that the closure binding is not used // outside the closure itself, we can avoid worst-case behavior // and only clear vars that are modified in the closure. hitDFBarrier = true; } else { // Black hole -- cannot analyze hitDFBarrier = true; } } } else { // We dont know how to optimize this instruction. // So, we assume we dont know type of the result. // TOP/class --> BOTTOM setOperandType(tmpState, dst, Object.class); } if (dirtied) { tmpState.unboxedVars.add(dst); tmpState.unboxedDirtyVars.add(dst); } else { // Since the instruction didn't run in unboxed form, // dirty unboxed vars will have to get boxed here. updateUnboxedVarsInfo(i, tmpState, dst, hasExceptionsRescued(), hitDFBarrier); } }