Skip to content


Browse files Browse the repository at this point in the history
OptimizeTempVarsPass is now just a collection of static methods and n…
…ot inheriting from CompilerPass.

clonedInstrs is no longer a field in IRScope and is a local in prepareFullBuildCommon.
  • Loading branch information
enebo committed Mar 4, 2015
1 parent 0dbe1b2 commit 88eeb49
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 58 deletions.
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/ir/
Expand Up @@ -2,6 +2,7 @@

import java.util.EnumSet;
import org.jruby.RubyInstanceConfig;
Expand Down Expand Up @@ -31,7 +32,6 @@ public class IRManager {

private final CompilerPass deadCodeEliminationPass = new DeadCodeElimination();
private final CompilerPass optimizeDynScopesPass = new OptimizeDynScopesPass();
private final CompilerPass optimizeTempVarsPass = new OptimizeTempVarsPass();
private final CompilerPass optimizeDelegationPass = new OptimizeDelegationPass();

private int dummyMetaClassCount = 0;
Expand Down Expand Up @@ -219,9 +219,9 @@ public TemporaryLocalVariable newTemporaryLocalVariable(int index) {
return tempVar;

public void optimizeTemporaryVariablesIfEnabled(IRScope scope) {
public Instr[] optimizeTemporaryVariablesIfEnabled(IRScope scope, Instr[] instrs) {
// FIXME: Make this check ir.passes and not run if ir.passes is set and does not contain opttempvars.;
return OptimizeTempVarsPass.optimizeTmpVars(scope, instrs);

Expand Down
35 changes: 8 additions & 27 deletions core/src/main/java/org/jruby/ir/
Expand Up @@ -96,8 +96,6 @@ public abstract class IRScope implements ParseResult {
/** -X-C full interpretation OR JIT depends on this */
protected FullInterpreterContext fullInterpreterContext;

private Instr[] clonedInstrs = null;

protected int temporaryVariableIndex;
protected int floatVariableIndex;
protected int fixnumVariableIndex;
Expand Down Expand Up @@ -447,40 +445,31 @@ public InterpreterContext allocateInterpreterContext(List<Instr> instructions) {
return interpreterContext;

protected void cloneInstrs() {
cloneInstrs(new SimpleCloneInfo(this, false));
private Instr[] cloneInstrs() {
SimpleCloneInfo cloneInfo = new SimpleCloneInfo(this, false);

public void cloneInstrs(SimpleCloneInfo cloneInfo) {
Instr[] instructions = interpreterContext.getInstructions();
int length = instructions.length;
setClonedInstrs(new Instr[length]);
Instr[] newInstructions = new Instr[length];

for (int i = 0; i < length; i++) {
clonedInstrs[i] = instructions[i].clone(cloneInfo);
newInstructions[i] = instructions[i].clone(cloneInfo);

for (IRClosure cl: getClosures()) {
// Closure may have independently been promoted to full build already
if (cl.fullInterpreterContext == null) {
return newInstructions;

protected void prepareFullBuildCommon() {
// Clone instrs from startup interpreter so we do not swap out instrs out from under the
// startup interpreter as we are building the full interpreter.
Instr[] instrs = cloneInstrs();

// This is a complicating pseudo-pass which needs to be run before CFG is generated. This
// necessitates us needing a clonedInstrs field on IRScope. If we can rewrite this to a full
// CFG using pass we can eliminate this intermediate save and field.
instrs = getManager().optimizeTemporaryVariablesIfEnabled(this, instrs);

fullInterpreterContext = new FullInterpreterContext(this, clonedInstrs);

setClonedInstrs(null); // boo. vestigial temporal field...because of opt tmp vars pass.
fullInterpreterContext = new FullInterpreterContext(this, instrs);
* This initializes a more complete(full) InterpreterContext which if used in mixed mode will be
Expand Down Expand Up @@ -1036,12 +1025,4 @@ public void savePersistenceInfo(int offset, IRReaderDecoder file) {
// instructionsOffsetInfoPersistenceBuffer = offset;
// persistenceStore = file;

public Instr[] getClonedInstrs() {
return clonedInstrs;

public void setClonedInstrs(Instr[] clonedInstrs) {
this.clonedInstrs = clonedInstrs;
49 changes: 21 additions & 28 deletions core/src/main/java/org/jruby/ir/passes/
@@ -1,35 +1,28 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import java.util.*;

public class OptimizeTempVarsPass extends CompilerPass {
public String getLabel() {
return "Temporary Variable Reduction";

public Object execute(IRScope s, Object... data) {

return null;

public boolean invalidate(IRScope s) {
// This runs after IR is built and before CFG is built.
// Not reversible in the form it is written right now.
return false;

* Takes multiple single def-use temporary variables and reduces them to share the same temp variable.
* This ends up reducing the amount of allocation and most likely helps hotspot warm up in some way quicker.
* This traditionally was a compiler pass (extends CompilerPass) but it is special in that it is the only
* pass which does not require any supplementary datastructures. In fact, it cannot be run by the time
* a CFG is created. So it was de-CompilerPassed and called directly.
public class OptimizeTempVarsPass {
private static void allocVar(Operand oldVar, IRScope s, List<TemporaryVariable> freeVarsList, Map<Operand, Operand> newVarMap) {
// If we dont have a var mapping, get a new var -- try the free list first
// and if none available, allocate a fresh one
Expand All @@ -43,8 +36,8 @@ private static void freeVar(TemporaryVariable newVar, List<TemporaryVariable> fr
if (!freeVarsList.contains(newVar)) freeVarsList.add(0, newVar);

private static void optimizeTmpVars(IRScope s) {
List<Instr> instructions = new ArrayList<>(Arrays.asList(s.getClonedInstrs()));
public static Instr[] optimizeTmpVars(IRScope s, Instr[] initialInstrs) {
List<Instr> instructions = new ArrayList<>(Arrays.asList(initialInstrs));

// Pass 1: Analyze instructions and find use and def count of temporary variables
Map<TemporaryVariable, Instr> tmpVarUses = new HashMap<>();
Expand Down Expand Up @@ -208,7 +201,7 @@ else if (i instanceof CopyInstr) {
// NOTE: It is sufficient to just track last use for renaming purposes.
// At the first definition, we allocate a variable which then starts the live range
Map<TemporaryVariable, Integer> lastVarUseOrDef = new HashMap<TemporaryVariable, Integer>();
Map<TemporaryVariable, Integer> lastVarUseOrDef = new HashMap<>();
int iCount = -1;
for (Instr i: instructions) {
Expand Down Expand Up @@ -238,8 +231,8 @@ else if (i instanceof CopyInstr) {
// Pass 4: Reallocate temporaries based on last uses to minimize # of unique vars.
// Replace all single use operands with constants they were assigned to.
// Using operand -> operand signature because simplifyOperands works on operands
Map<Operand, Operand> newVarMap = new HashMap<Operand, Operand>();
List<TemporaryVariable> freeVarsList = new ArrayList<TemporaryVariable>();
Map<Operand, Operand> newVarMap = new HashMap<>();
List<TemporaryVariable> freeVarsList = new ArrayList<>();
iCount = -1;

Expand Down Expand Up @@ -273,6 +266,6 @@ else if (i instanceof CopyInstr) {

Instr[] newInstrs = new Instr[instructions.size()];
return newInstrs;

0 comments on commit 88eeb49

Please sign in to comment.