Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into non-indy-jit
Browse files Browse the repository at this point in the history
Conflicts:
	core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
  • Loading branch information
headius committed Oct 14, 2014
2 parents b2438df + 4a5d818 commit b7f248b
Show file tree
Hide file tree
Showing 35 changed files with 484 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.ir.*;
import org.jruby.ir.operands.InterpreterContext;
import org.jruby.ir.representations.CFG;
import org.jruby.ir.interpreter.Interpreter;
import org.jruby.ir.runtime.IRRuntimeHelpers;
Expand Down Expand Up @@ -139,8 +140,8 @@ public void ensureInstrsReady() {
// SSS FIXME: Move this out of here to some other place?
// Prepare method if not yet done so we know if the method has an explicit/implicit call protocol
if (method.getInstrsForInterpretation() == null) {
method.prepareForInterpretation(false);
this.pushScope = !method.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);
InterpreterContext context = method.prepareForInterpretation();
this.pushScope = !context.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);
}
}

Expand Down
44 changes: 29 additions & 15 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ public void addInstr(Instr i) {
instrs.add(i);
}

public void addInstrAtBeginning(Instr i) {
instrs.add(0, i);
}

public void emitBody(IRBuilder b, IRScope s) {
b.addInstr(s, new LabelInstr(start));
for (Instr i: instrs) {
Expand Down Expand Up @@ -293,6 +297,16 @@ public void addInstr(IRScope s, Instr i) {
}
}

public void addInstrAtBeginning(IRScope s, Instr i) {
// If we are building an ensure body, stash the instruction
// in the ensure body's list. If not, add it to the scope directly.
if (ensureBodyBuildStack.empty()) {
s.addInstrAtBeginning(i);
} else {
ensureBodyBuildStack.peek().addInstrAtBeginning(i);
}
}

private Operand getImplicitBlockArg(IRScope s) {
int n = 0;
while (s != null && s instanceof IRClosure) {
Expand Down Expand Up @@ -505,8 +519,7 @@ public Operand buildLambda(LambdaNode node, IRScope s) {
// can be U_NIL if the node is an if node with returns in both branches.
if (closureRetVal != U_NIL) closureBuilder.addInstr(closure, new ReturnInstr(closureRetVal));

// Added as part of 'prepareForInterpretation' code.
// handleBreakAndReturnsInLambdas(closure);
handleBreakAndReturnsInLambdas(closure);

Variable lambda = s.createTemporaryVariable();
// SSS FIXME: Is this the right self here?
Expand Down Expand Up @@ -891,8 +904,8 @@ private void handleNonlocalReturnInMethod(IRScope s) {
//
// Add label and marker instruction in reverse order to the beginning
// so that the label ends up being the first instr.
s.addInstrAtBeginning(new ExceptionRegionStartMarkerInstr(gebLabel));
s.addInstrAtBeginning(new LabelInstr(rBeginLabel));
addInstrAtBeginning(s, new ExceptionRegionStartMarkerInstr(gebLabel));
addInstrAtBeginning(s, new LabelInstr(rBeginLabel));
addInstr(s, new ExceptionRegionEndMarkerInstr());

// Receive exceptions (could be anything, but the handler only processes IRReturnJumps)
Expand Down Expand Up @@ -1970,19 +1983,13 @@ public void buildMultipleAsgn19Assignment(final MultipleAsgn19Node multipleAsgnN
}
}

/* ------------------------------------------------------------------
* This code is added on demand at runtime in the interpreter code.
* For JIT, this may have to be added always!
// These two methods could have been DRY-ed out if we had closures.
// For now, just duplicating code.
private void handleBreakAndReturnsInLambdas(IRClosure s) {
Label rBeginLabel = s.getNewLabel();
Label rEndLabel = s.getNewLabel();
Label rescueLabel = s.getNewLabel();
Label rescueLabel = Label.GLOBAL_ENSURE_BLOCK_LABEL;

// protect the entire body as it exists now with the global ensure block
s.addInstrAtBeginning(new ExceptionRegionStartMarkerInstr(rescueLabel));
addInstrAtBeginning(s, new ExceptionRegionStartMarkerInstr(rescueLabel));
addInstr(s, new ExceptionRegionEndMarkerInstr());

// Receive exceptions (could be anything, but the handler only processes IRBreakJumps)
Expand All @@ -1992,14 +1999,13 @@ private void handleBreakAndReturnsInLambdas(IRClosure s) {

// Handle break using runtime helper
// --> IRRuntimeHelpers.handleBreakAndReturnsInLambdas(context, scope, bj, blockType)
Variable ret = createTemporaryVariable();
addInstr(s, new RuntimeHelperCall(ret, "handleBreakAndReturnsInLambdas", new Operand[]{exc} ));
Variable ret = s.createTemporaryVariable();
addInstr(s, new RuntimeHelperCall(ret, RuntimeHelperCall.Methods.HANDLE_BREAK_AND_RETURNS_IN_LAMBDA, new Operand[]{exc} ));
addInstr(s, new ReturnInstr(ret));

// End
addInstr(s, new LabelInstr(rEndLabel));
}
* ------------------------------------------------------------------ */

public void receiveMethodArgs(final ArgsNode argsNode, IRScope s) {
receiveArgs(argsNode, s);
Expand Down Expand Up @@ -2524,6 +2530,14 @@ public Operand buildIter(final IterNode iterNode, IRScope s) {
closureBuilder.addInstr(closure, new ReturnInstr(closureRetVal));
}

// Always add break/return handling even though this
// is only required for lambdas, but we don't know at this time,
// if this is a lambda or not.
//
// SSS FIXME: At a later time, see if we can optimize this and
// do this on demand.
closureBuilder.handleBreakAndReturnsInLambdas(closure);

return new WrappedIRClosure(s.getSelf(), closure);
}

Expand Down
45 changes: 0 additions & 45 deletions core/src/main/java/org/jruby/ir/IRClosure.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public class IRClosure extends IRScope {

private Arity arity;
private int argumentType;
public boolean addedGEBForUncaughtBreaks;

/** Added for interp/JIT purposes */
private BlockBody body;
Expand Down Expand Up @@ -78,7 +77,6 @@ protected IRClosure(IRClosure c, IRScope lexicalParent, int closureId, String fu
} else {
this.body = new InterpretedIRBlockBody(this, c.body.arity(), c.body.getArgumentType());
}
this.addedGEBForUncaughtBreaks = false;
this.blockArgs = new ArrayList<Operand>();
this.arity = c.arity;
}
Expand Down Expand Up @@ -292,7 +290,6 @@ protected IRClosure cloneForInlining(CloneInfo ii, IRClosure clone) {
// FIXME: This is fragile. Untangle this state.
// Why is this being copied over to InterpretedIRBlockBody?
clone.setParameterList(this.parameterList);
clone.addedGEBForUncaughtBreaks = this.addedGEBForUncaughtBreaks;
clone.isBeginEndBlock = this.isBeginEndBlock;

SimpleCloneInfo clonedII = ii.cloneForCloningClosure(clone);
Expand Down Expand Up @@ -327,48 +324,6 @@ public IRClosure cloneForInlining(CloneInfo ii) {
return cloneForInlining(ii, clonedClosure);
}

// Add a global-ensure-block to catch uncaught breaks
// This is usually required only if this closure is being
// used as a lambda, but it is safe to add this for any closure

protected boolean addGEBForUncaughtBreaks() {
// Nothing to do if already done
if (addedGEBForUncaughtBreaks) {
return false;
}

CFG cfg = cfg();
BasicBlock geb = cfg.getGlobalEnsureBB();
if (geb == null) {
geb = new BasicBlock(cfg, new Label("_GLOBAL_ENSURE_BLOCK", 0));
Variable exc = createTemporaryVariable();
geb.addInstr(new ReceiveJRubyExceptionInstr(exc)); // JRuby implementation exception
// Handle uncaught break and non-local returns using runtime helpers
Variable ret = createTemporaryVariable();
geb.addInstr(new RuntimeHelperCall(ret,
RuntimeHelperCall.Methods.HANDLE_BREAK_AND_RETURNS_IN_LAMBDA, new Operand[]{exc} ));
geb.addInstr(new ReturnInstr(ret));
cfg.addGlobalEnsureBB(geb);
} else {
// SSS FIXME: Assumptions:
//
// First instr is a 'ReceiveExceptionBase'
// Last instr is a 'ThrowExceptionInstr' -- replaced by handleBreakAndReturnsInLambdas

List<Instr> instrs = geb.getInstrs();
Variable exc = ((ReceiveExceptionBase)instrs.get(0)).getResult();
Variable ret = createTemporaryVariable();
instrs.set(instrs.size()-1, new RuntimeHelperCall(ret,
RuntimeHelperCall.Methods.HANDLE_BREAK_AND_RETURNS_IN_LAMBDA, new Operand[]{exc} ));
geb.addInstr(new ReturnInstr(ret));
}

// Update scope
addedGEBForUncaughtBreaks = true;

return true;
}

@Override
public void setName(String name) {
// We can distinguish closures only with parent scope name
Expand Down
57 changes: 18 additions & 39 deletions core/src/main/java/org/jruby/ir/IRScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public abstract class IRScope implements ParseResult {
/** What passes have been run on this scope? */
private List<CompilerPass> executedPasses;

private Instr[] linearizedInstrArray;
/** What the interpreter depends on to interpret this IRScope */
private InterpreterContext interpreterContext;
private List<BasicBlock> linearizedBBList;
protected int temporaryVariableIndex;
protected int floatVariableIndex;
Expand Down Expand Up @@ -155,7 +156,7 @@ protected IRScope(IRScope s, IRScope lexicalParent) {
this.dfProbs = new HashMap<String, DataFlowProblem>();
this.nextVarIndex = new HashMap<String, Integer>(); // SSS FIXME: clone!
this.cfg = null;
this.linearizedInstrArray = null;
this.interpreterContext = null;
this.linearizedBBList = null;

this.flagsComputed = s.flagsComputed;
Expand Down Expand Up @@ -187,7 +188,7 @@ public IRScope(IRManager manager, IRScope lexicalParent, String name,
this.dfProbs = new HashMap<String, DataFlowProblem>();
this.nextVarIndex = new HashMap<String, Integer>();
this.cfg = null;
this.linearizedInstrArray = null;
this.interpreterContext = null;
this.linearizedBBList = null;
this.flagsComputed = false;
flags.remove(CAN_RECEIVE_BREAKS);
Expand Down Expand Up @@ -466,10 +467,10 @@ public CFG getCFG() {
return cfg;
}

private synchronized Instr[] prepareInstructions() {
private synchronized InterpreterContext prepareInstructions() {
checkRelinearization();

if (linearizedInstrArray != null) return linearizedInstrArray; // Already prepared
if (interpreterContext != null) return interpreterContext; // Already prepared

setupLinearization();

Expand Down Expand Up @@ -520,7 +521,7 @@ private synchronized Instr[] prepareInstructions() {
// System.out.println("SCOPE: " + getName());
// System.out.println("INSTRS: " + cfg().toStringInstrs());

linearizedInstrArray = newInstrs.toArray(new Instr[newInstrs.size()]);
Instr[] linearizedInstrArray = newInstrs.toArray(new Instr[newInstrs.size()]);

// Pass 2: Use ipc info from previous to mark all linearized instrs rpc
ipc = 0;
Expand All @@ -537,7 +538,10 @@ private synchronized Instr[] prepareInstructions() {
}
}

return linearizedInstrArray;
interpreterContext = new InterpreterContext(getTemporaryVariablesCount(), getBooleanVariablesCount(),
getFixnumVariablesCount(), getFloatVariablesCount(),getFlags().clone(), linearizedInstrArray);

return interpreterContext;
}

private boolean isUnsafeScope() {
Expand Down Expand Up @@ -605,7 +609,7 @@ private void optimizeSimpleScopes() {
}
}

private void initScope(boolean isLambda, boolean jitMode) {
private void initScope(boolean jitMode) {
// Reset linearization, if any exists
resetLinearizationData();

Expand All @@ -614,15 +618,6 @@ private void initScope(boolean isLambda, boolean jitMode) {
buildCFG();
}

if (isLambda) {
// Add a global ensure block to catch uncaught breaks
// and throw a LocalJumpError.
if (((IRClosure)this).addGEBForUncaughtBreaks()) {
resetState();
computeScopeFlags();
}
}

runCompilerPasses(getManager().getCompilerPasses(this));

if (!jitMode && RubyInstanceConfig.IR_COMPILER_PASSES == null) {
Expand All @@ -636,13 +631,11 @@ private void initScope(boolean isLambda, boolean jitMode) {
}

/** Run any necessary passes to get the IR ready for interpretation */
public synchronized Instr[] prepareForInterpretation(boolean isLambda) {
initScope(isLambda, false);
public synchronized InterpreterContext prepareForInterpretation() {
initScope(false);

checkRelinearization();

if (linearizedInstrArray != null) return linearizedInstrArray;

// System.out.println("-- passes run for: " + this + " = " + java.util.Arrays.toString(executedPasses.toArray()));

// Linearize CFG, etc.
Expand All @@ -652,14 +645,7 @@ public synchronized Instr[] prepareForInterpretation(boolean isLambda) {
/* SSS FIXME: Do we need to synchronize on this? Cache this info in a scope field? */
/** Run any necessary passes to get the IR ready for compilation */
public synchronized List<BasicBlock> prepareForCompilation() {
// For lambdas, we need to add a global ensure block to catch
// uncaught breaks and throw a LocalJumpError.
//
// Since we dont re-JIT a previously JIT-ted closure,
// mark all closures lambdas always. But, check if there are
// other smarts available to us and eliminate adding
// this code to every closure there is.
initScope(this instanceof IRClosure, true);
initScope(true);

runCompilerPasses(getManager().getJITPasses(this));

Expand Down Expand Up @@ -1062,15 +1048,8 @@ public List<Instr> getInstrs() {
return instrList;
}

public Instr[] getInstrsForInterpretation() {
return linearizedInstrArray;
}

public Instr[] getInstrsForInterpretation(boolean isLambda) {
if (linearizedInstrArray == null) {
prepareForInterpretation(isLambda);
}
return linearizedInstrArray;
public InterpreterContext getInstrsForInterpretation() {
return interpreterContext;
}

public void resetLinearizationData() {
Expand Down Expand Up @@ -1113,7 +1092,7 @@ public CFG cfg() {

public void resetState() {
relinearizeCFG = true;
linearizedInstrArray = null;
interpreterContext = null;
cfg.resetState();

// reset flags
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/IRScriptBody.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public boolean isScriptScope() {
}

public IRubyObject interpret(ThreadContext context, IRubyObject self) {
prepareForInterpretation(false);
prepareForInterpretation();

String name = "(root)";
if (IRRuntimeHelpers.isDebug()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,21 @@ public void addStores(Map<Operand, Operand> varRenameMap) {

// Allocate global-ensure block, if necessary
if ((mightRequireGlobalEnsureBlock == true) && !dirtyVars.isEmpty()) {
Variable exc = cfgScope.createTemporaryVariable();
BasicBlock geb = new BasicBlock(cfg, new Label("_GLOBAL_ENSURE_BLOCK", 0));

ListIterator instrs = geb.getInstrs().listIterator();
ListIterator<Instr> instrs;
BasicBlock geb = cfg.getGlobalEnsureBB();
if (geb == null) {
Variable exc = cfgScope.createTemporaryVariable();
geb = new BasicBlock(cfg, Label.GLOBAL_ENSURE_BLOCK_LABEL);
geb.addInstr(new ReceiveJRubyExceptionInstr(exc)); // JRuby implementation exception handling
geb.addInstr(new ThrowExceptionInstr(exc));
cfg.addGlobalEnsureBB(geb);
}

instrs.add(new ReceiveJRubyExceptionInstr(exc)); // JRuby implementation exception handling
instrs = geb.getInstrs().listIterator(geb.getInstrs().size());
Instr i = instrs.previous();
// Assumption: Last instr should always be a control-transfer instruction
assert i.getOperation().transfersControl(): "Last instruction of GEB in scope: " + getScope() + " is " + i + ", not a control-xfer instruction";
addClosureExitStoreLocalVars(instrs, dirtyVars, varRenameMap);
instrs.add(new ThrowExceptionInstr(exc));

cfg.addGlobalEnsureBB(geb);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ public void visit(IRVisitor visitor) {

@Override
public String toString() {
return result + "`" + (pieces == null ? "[]" : pieces) + "`";
return result + " = `" + (pieces == null ? "[]" : pieces) + "`";
}
}
Loading

0 comments on commit b7f248b

Please sign in to comment.