CloneInfo.java
package org.jruby.ir.transformations.inlining;
import java.util.HashMap;
import java.util.Map;
import org.jruby.ir.IRClosure;
import org.jruby.ir.IRScope;
import org.jruby.ir.operands.Label;
import org.jruby.ir.operands.Self;
import org.jruby.ir.operands.Variable;
/**
* Base class for cloning context object. Simple cloning and inline cloning both have
* some common state and logic such as needing to maintain references to new constructed
* replacement labels and variables.
*/
public abstract class CloneInfo {
protected Map<Label, Label> labelRenameMap = new HashMap<>();
protected Map<Variable, Variable> variableRenameMap = new HashMap<>();
protected IRScope scope; // clone and inlining use this field differently.
// Only used by subclasses
protected CloneInfo(IRScope scope) {
this.scope = scope;
}
public SimpleCloneInfo cloneForCloningClosure(IRClosure clonedClosure) {
// If cloning for ensure block cloning we want to propagate that to child closure clones
boolean ensureClone = this instanceof SimpleCloneInfo && ((SimpleCloneInfo) this).isEnsureBlockCloneMode();
SimpleCloneInfo clone = new SimpleCloneInfo(clonedClosure, ensureClone);
for (Variable v: variableRenameMap.keySet()) {
clone.variableRenameMap.put(v, variableRenameMap.get(v));
}
return clone;
}
/**
* @return The IRScope this cloning operation is happening in (or is coming from).
*/
public IRScope getScope() {
return scope;
}
protected abstract Label getRenamedLabelSimple(Label l);
/**
* Return a new instance of a label for the newly cloned scope. Maps are maintained
* because Labels expect to share the same instance across a CFG.
*
* @param label to be renamed.
* @return the new Label
*/
public Label getRenamedLabel(Label label) {
if (Label.UNRESCUED_REGION_LABEL.equals(label)) return label; // Special case -- is there a way to avoid this?
Label newLabel = this.labelRenameMap.get(label);
if (newLabel == null) {
newLabel = getRenamedLabelSimple(label);
this.labelRenameMap.put(label, newLabel);
}
return newLabel;
}
/**
* How do we rename %self?
*
* @param self to be renamed
* @return the new self or itself
*/
protected abstract Variable getRenamedSelfVariable(Variable self);
/**
* How are typical variables renamed if they were not yet found in the variable renaming map?
*
* @param variable to be renamed
* @return the new variable
*/
protected abstract Variable getRenamedVariableSimple(Variable variable);
/**
* Return a new instance of a variable for the newly cloned scope. Maps are maintained
* because Variables typically share the same instance accross a CFG (of the same lexical depth).
*
* @param variable to be renamed
* @return the new Variable
*/
public Variable getRenamedVariable(Variable variable) {
if (variable instanceof Self) getRenamedSelfVariable(variable);
Variable newVariable = variableRenameMap.get(variable);
if (newVariable == null) {
newVariable = getRenamedVariableSimple(variable);
variableRenameMap.put(variable, newVariable);
}
return newVariable;
}
}