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.
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
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
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
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
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
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);
}
}
}
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) + "`";
}
}

0 comments on commit b7f248b

Please sign in to comment.