CloneInfo.java

  1. package org.jruby.ir.transformations.inlining;

  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import org.jruby.ir.IRClosure;
  5. import org.jruby.ir.IRScope;
  6. import org.jruby.ir.operands.Label;
  7. import org.jruby.ir.operands.Self;
  8. import org.jruby.ir.operands.Variable;

  9. /**
  10.  * Base class for cloning context object.  Simple cloning and inline cloning both have
  11.  * some common state and logic such as needing to maintain references to new constructed
  12.  * replacement labels and variables.
  13.  */
  14. public abstract class CloneInfo {
  15.     protected Map<Label, Label> labelRenameMap = new HashMap<>();
  16.     protected Map<Variable, Variable> variableRenameMap = new HashMap<>();
  17.     protected IRScope scope; // clone and inlining use this field differently.

  18.     // Only used by subclasses
  19.     protected CloneInfo(IRScope scope) {
  20.         this.scope = scope;
  21.     }

  22.     public SimpleCloneInfo cloneForCloningClosure(IRClosure clonedClosure) {
  23.         // If cloning for ensure block cloning we want to propagate that to child closure clones
  24.         boolean ensureClone = this instanceof SimpleCloneInfo && ((SimpleCloneInfo) this).isEnsureBlockCloneMode();
  25.         SimpleCloneInfo clone = new SimpleCloneInfo(clonedClosure, ensureClone);

  26.         for (Variable v: variableRenameMap.keySet()) {
  27.             clone.variableRenameMap.put(v, variableRenameMap.get(v));
  28.         }

  29.         return clone;
  30.     }

  31.     /**
  32.      * @return The IRScope this cloning operation is happening in (or is coming from).
  33.      */
  34.     public IRScope getScope() {
  35.         return scope;
  36.     }

  37.     protected abstract Label getRenamedLabelSimple(Label l);

  38.     /**
  39.      * Return a new instance of a label for the newly cloned scope.  Maps are maintained
  40.      * because Labels expect to share the same instance across a CFG.
  41.      *
  42.      * @param label to be renamed.
  43.      * @return the new Label
  44.      */
  45.     public Label getRenamedLabel(Label label) {
  46.         if (Label.UNRESCUED_REGION_LABEL.equals(label)) return label; // Special case -- is there a way to avoid this?

  47.         Label newLabel = this.labelRenameMap.get(label);
  48.         if (newLabel == null) {
  49.             newLabel = getRenamedLabelSimple(label);
  50.             this.labelRenameMap.put(label, newLabel);
  51.         }
  52.         return newLabel;
  53.     }

  54.     /**
  55.      * How do we rename %self?
  56.      *
  57.      * @param self to be renamed
  58.      * @return the new self or itself
  59.      */
  60.     protected abstract Variable getRenamedSelfVariable(Variable self);

  61.     /**
  62.      * How are typical variables renamed if they were not yet found in the variable renaming map?
  63.      *
  64.      * @param variable to be renamed
  65.      * @return the new variable
  66.      */
  67.     protected abstract Variable getRenamedVariableSimple(Variable variable);

  68.     /**
  69.      * Return a new instance of a variable for the newly cloned scope.  Maps are maintained
  70.      * because Variables typically share the same instance accross a CFG (of the same lexical depth).
  71.      *
  72.      * @param variable to be renamed
  73.      * @return the new Variable
  74.      */
  75.     public Variable getRenamedVariable(Variable variable) {
  76.         if (variable instanceof Self) getRenamedSelfVariable(variable);

  77.         Variable newVariable = variableRenameMap.get(variable);
  78.         if (newVariable == null) {
  79.             newVariable = getRenamedVariableSimple(variable);
  80.             variableRenameMap.put(variable, newVariable);
  81.         }

  82.         return newVariable;
  83.     }
  84. }