Skip to content

Commit

Permalink
Showing 20 changed files with 359 additions and 403 deletions.
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@

import org.jruby.RubyModule;
import org.jruby.ir.*;
import org.jruby.ir.operands.InterpreterContext;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
@@ -39,7 +39,7 @@ protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject sel
// Add a parent-link to current dynscope to support non-local returns cheaply
// This doesn't affect variable scoping since local variables will all have
// the right scope depth.
context.pushScope(DynamicScope.newDynamicScope(method.getStaticScope(), context.getCurrentScope()));
context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope(), context.getCurrentScope()));
}
context.setCurrentVisibility(getVisibility());
}
Original file line number Diff line number Diff line change
@@ -8,9 +8,9 @@
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.interpreter.InterpreterContext;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Arity;
@@ -127,10 +127,9 @@ protected void post(InterpreterContext ic, ThreadContext context) {

protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject self, String name, Block block) {
// update call stacks (push: frame, class, scope, etc.)
StaticScope ss = method.getStaticScope();
context.preMethodFrameOnly(getImplementationClass(), name, self, block);
if (ic.pushNewDynScope()) {
context.pushScope(DynamicScope.newDynamicScope(method.getStaticScope()));
context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope()));
}
context.setCurrentVisibility(getVisibility());
}
29 changes: 7 additions & 22 deletions core/src/main/java/org/jruby/ir/IRClosure.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package org.jruby.ir;

import org.jruby.ir.instructions.*;
import org.jruby.ir.interpreter.ClosureInterpreterContext;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.operands.*;
import org.jruby.ir.representations.BasicBlock;
import org.jruby.ir.representations.CFG;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
@@ -77,7 +78,7 @@ protected IRClosure(IRClosure c, IRScope lexicalParent, int closureId, String fu
} else {
this.body = new InterpretedIRBlockBody(this, c.body.arity(), c.body.getArgumentType());
}
this.blockArgs = new ArrayList<Operand>();
this.blockArgs = new ArrayList<>();
this.arity = c.arity;
}

@@ -91,7 +92,7 @@ public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, Stati

public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Arity arity, int argumentType, String prefix, boolean isBeginEndBlock) {
this(manager, lexicalParent, lexicalParent.getFileName(), lineNumber, staticScope, prefix);
this.blockArgs = new ArrayList<Operand>();
this.blockArgs = new ArrayList<>();
this.argumentType = argumentType;
this.arity = arity;
lexicalParent.addClosure(this);
@@ -109,25 +110,9 @@ public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, Stati
this.nestingDepth++;
}

public InterpreterContext prepareInterpreterContext(Operand self) {
if (interpreterContext != null) return interpreterContext; // Already prepared

initScope(false);

Instr[] linearizedInstrArray = prepareInstructions();

interpreterContext = new ClosureInterpreterContext(getTemporaryVariablesCount(), getBooleanVariablesCount(),
getFixnumVariablesCount(), getFloatVariablesCount(), getFlags(), linearizedInstrArray,
self, getStaticScope(), getBlockBody());

return interpreterContext;
}

@Override
public synchronized InterpreterContext prepareForInterpretation() {
// This should have already been prepared during preparation of parent scopes.
// If this is null, it would be a bug and let users throw a NPE.
return interpreterContext;
public InterpreterContext allocateInterpreterContext(Instr[] instructionList) {
return new ClosureInterpreterContext(this, instructionList);
}

public void setBeginEndBlock() {
@@ -271,7 +256,7 @@ public LocalVariable getLocalVariable(String name, int depth) {
//
// In "(a)", it is 0 (correct), but in the body, it is 1 (incorrect)

LocalVariable lvar = null;
LocalVariable lvar;
IRScope s = this;
int d = depth;
do {
13 changes: 8 additions & 5 deletions core/src/main/java/org/jruby/ir/IRScope.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@
import org.jruby.RubyModule;
import org.jruby.ir.dataflow.DataFlowProblem;
import org.jruby.ir.instructions.*;
import org.jruby.ir.interpreter.ClosureInterpreterContext;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.operands.*;
import org.jruby.ir.operands.Float;
import org.jruby.ir.passes.CompilerPass;
@@ -611,6 +613,11 @@ protected void initScope(boolean jitMode) {
}
}

/** Make version specific to scope which needs it (e.g. Closure vs non-closure). */
public InterpreterContext allocateInterpreterContext(Instr[] instructionList) {
return new InterpreterContext(this, instructionList);
}

/** Run any necessary passes to get the IR ready for interpretation */
public synchronized InterpreterContext prepareForInterpretation() {
if (interpreterContext != null) return interpreterContext; // Already prepared
@@ -619,11 +626,7 @@ public synchronized InterpreterContext prepareForInterpretation() {

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

// Linearize CFG, etc.
Instr[] linearizedInstrArray = prepareInstructions();

interpreterContext = new InterpreterContext(getTemporaryVariablesCount(), getBooleanVariablesCount(),
getFixnumVariablesCount(), getFloatVariablesCount(), getFlags(), linearizedInstrArray);
interpreterContext = allocateInterpreterContext(prepareInstructions());

return interpreterContext;
}
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@ public Object interpret(ThreadContext context, StaticScope currScope, DynamicSco
// SSS FIXME: Copied this from ast/LambdaNode ... Is this required here as well?
//
// JRUBY-5686: do this before executing so first time sets cref module
((ClosureInterpreterContext)getLambdaBody()).getStaticScope().determineModule();
((WrappedIRClosure) getLambdaBody()).getClosure().getStaticScope().determineModule();

// CON: This must not be happening, because nil would never cast to Block
// IRClosure body = getLambdaBody().getClosure();
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.jruby.ir.interpreter;

import org.jruby.ir.IRClosure;
import org.jruby.ir.instructions.Instr;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;

/**
* Interpreter knowledge needed to interpret a closure.
*/
public class ClosureInterpreterContext extends InterpreterContext {
public ClosureInterpreterContext(IRClosure scope, Instr[] instructions) {
super(scope, instructions);
}

/**
* Blocks have more complicated logic for pushing a dynamic scope (see InterpretedIRBlockBody).
* We throw an error in case somehow we mistakenly try and push a binding.
*/
@Override
public DynamicScope newDynamicScope(ThreadContext context) {
throw new RuntimeException("We do not push bindings for closures");
}
}
69 changes: 27 additions & 42 deletions core/src/main/java/org/jruby/ir/interpreter/Interpreter.java
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ public static void dumpStats() {
}
}

private static IRScope getEvalContainerScope(StaticScope evalScope, EvalType evalType) {
private static IRScope getEvalContainerScope(StaticScope evalScope) {
// We cannot get the containing IR scope from evalScope because of static-scope wrapping
// that is going on.
// 1. In all cases, DynamicScope.getEvalScope wraps the executing static scope in a new local scope.
@@ -76,18 +76,16 @@ private static IRScope getEvalContainerScope(StaticScope evalScope, EvalType eva

public static IRubyObject interpretCommonEval(Ruby runtime, String file, int lineNumber, String backtraceName, RootNode rootNode, IRubyObject self, Block block, EvalType evalType) {
StaticScope ss = rootNode.getStaticScope();
IRScope containingIRScope = getEvalContainerScope(ss, evalType);
IRScope containingIRScope = getEvalContainerScope(ss);
IREvalScript evalScript = IRBuilder.createIRBuilder(runtime, runtime.getIRManager()).buildEvalRoot(ss, containingIRScope, file, lineNumber, rootNode, evalType);
// ClosureInterpreterContext never retrieved as an operand in this context.
// So, self operand is not required here.
// Passing null to force early crasher if ever used differently.
evalScript.prepareInterpreterContext(null);
evalScript.prepareForInterpretation();
ThreadContext context = runtime.getCurrentContext();

IRubyObject rv = null;
DynamicScope s = null;

s = rootNode.getScope();
DynamicScope s = rootNode.getScope();
s.setEvalType(evalType);
context.pushScope(s);

@@ -124,7 +122,7 @@ public static void runBeginEndBlocks(List<IRClosure> beBlocks, ThreadContext con

for (IRClosure b: beBlocks) {
// SSS FIXME: Should I piggyback on WrappedIRClosure.retrieve or just copy that code here?
b.prepareInterpreterContext(b.getSelf());
b.prepareForInterpretation();
Block blk = (Block)(new WrappedIRClosure(b.getSelf(), b)).retrieve(context, self, currScope, context.getCurrentScope(), temp);
blk.yield(context, null);
}
@@ -219,11 +217,11 @@ private static void setFixnumVar(long[] fixnums, TemporaryLocalVariable var, lon
fixnums[var.offset] = val;
}

private static void setBooleanVar(ThreadContext context, boolean[] booleans, TemporaryLocalVariable var, boolean val) {
private static void setBooleanVar(boolean[] booleans, TemporaryLocalVariable var, boolean val) {
booleans[var.offset] = val;
}

private static void interpretIntOp(AluInstr instr, Operation op, ThreadContext context, long[] fixnums, boolean[] booleans, Object[] temp) {
private static void interpretIntOp(AluInstr instr, Operation op, long[] fixnums, boolean[] booleans) {
TemporaryLocalVariable dst = (TemporaryLocalVariable)instr.getResult();
long i1 = getFixnumArg(fixnums, instr.getArg1());
long i2 = getFixnumArg(fixnums, instr.getArg2());
@@ -237,14 +235,14 @@ private static void interpretIntOp(AluInstr instr, Operation op, ThreadContext c
case IXOR: setFixnumVar(fixnums, dst, i1 ^ i2); break;
case ISHL: setFixnumVar(fixnums, dst, i1 << i2); break;
case ISHR: setFixnumVar(fixnums, dst, i1 >> i2); break;
case ILT : setBooleanVar(context, booleans, dst, i1 < i2); break;
case IGT : setBooleanVar(context, booleans, dst, i1 > i2); break;
case IEQ : setBooleanVar(context, booleans, dst, i1 == i2); break;
case ILT : setBooleanVar(booleans, dst, i1 < i2); break;
case IGT : setBooleanVar(booleans, dst, i1 > i2); break;
case IEQ : setBooleanVar(booleans, dst, i1 == i2); break;
default: throw new RuntimeException("Unhandled int op: " + op + " for instr " + instr);
}
}

private static void interpretFloatOp(AluInstr instr, Operation op, ThreadContext context, double[] floats, boolean[] booleans, Object[] temp) {
private static void interpretFloatOp(AluInstr instr, Operation op, double[] floats, boolean[] booleans) {
TemporaryLocalVariable dst = (TemporaryLocalVariable)instr.getResult();
double a1 = getFloatArg(floats, instr.getArg1());
double a2 = getFloatArg(floats, instr.getArg2());
@@ -253,9 +251,9 @@ private static void interpretFloatOp(AluInstr instr, Operation op, ThreadContext
case FSUB: setFloatVar(floats, dst, a1 - a2); break;
case FMUL: setFloatVar(floats, dst, a1 * a2); break;
case FDIV: setFloatVar(floats, dst, a1 / a2); break;
case FLT : setBooleanVar(context, booleans, dst, a1 < a2); break;
case FGT : setBooleanVar(context, booleans, dst, a1 > a2); break;
case FEQ : setBooleanVar(context, booleans, dst, a1 == a2); break;
case FLT : setBooleanVar(booleans, dst, a1 < a2); break;
case FGT : setBooleanVar(booleans, dst, a1 > a2); break;
case FEQ : setBooleanVar(booleans, dst, a1 == a2); break;
default: throw new RuntimeException("Unhandled float op: " + op + " for instr " + instr);
}
}
@@ -288,7 +286,6 @@ private static void receiveArg(ThreadContext context, Instr i, Operation operati
default:
result = ((ReceiveArgBase)instr).receiveArg(context, args, acceptsKeywordArgument);
setResult(temp, currDynScope, instr.getResult(), result);
return;
}
}

@@ -346,7 +343,7 @@ private static void processCall(ThreadContext context, Instr instr, Operation op

private static void processBookKeepingOp(ThreadContext context, Instr instr, Operation operation,
String name, IRubyObject[] args, IRubyObject self, Block block,
RubyModule implClass, Visibility visibility, Object[] temp, DynamicScope currDynamicScope) {
RubyModule implClass, Visibility visibility) {
switch(operation) {
case PUSH_FRAME:
context.preMethodFrameOnly(implClass, name, self, block);
@@ -511,21 +508,6 @@ private static void processOtherOp(ThreadContext context, Instr instr, Operation
}
}

private static DynamicScope getNewDynScope(ThreadContext context, IRScope scope, StaticScope currScope) {
// SSS NOTE: Method/module scopes only!
//
// Blocks are a headache -- so, these instrs. are only added to IRMethods.
// Blocks have more complicated logic for pushing a dynamic scope (see InterpretedIRBlockBody)
if (scope instanceof IRMetaClassBody) {
// Add a parent-link to current dynscope to support non-local returns cheaply
// This doesn't affect variable scoping since local variables will all have
// the right scope depth.
return DynamicScope.newDynamicScope(currScope, context.getCurrentScope());
} else {
return DynamicScope.newDynamicScope(currScope);
}
}

private static IRubyObject interpret(ThreadContext context, IRubyObject self,
IRScope scope, Visibility visibility, RubyModule implClass, String name, IRubyObject[] args, Block block, Block.Type blockType) {
InterpreterContext interpreterContext = scope.getInterpreterContext();
@@ -542,13 +524,13 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
int ipc = 0;
Object exception = null;
DynamicScope currDynScope = context.getCurrentScope();
StaticScope currScope = scope.getStaticScope();
StaticScope currScope = interpreterContext.getStaticScope();

// Init profiling this scope
boolean debug = IRRuntimeHelpers.isDebug();
boolean profile = IRRuntimeHelpers.inProfileMode();
Integer scopeVersion = profile ? Profiler.initProfiling(scope) : 0;
boolean acceptsKeywordArgument = scope.receivesKeywordArgs();
//Integer scopeVersion = profile ? Profiler.initProfiling(scope) : 0;
boolean acceptsKeywordArgument = interpreterContext.receivesKeywordArguments();

// Enter the looooop!
while (ipc < n) {
@@ -566,16 +548,16 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
try {
switch (operation.opClass) {
case INT_OP:
interpretIntOp((AluInstr) instr, operation, context, fixnums, booleans, temp);
interpretIntOp((AluInstr) instr, operation, fixnums, booleans);
break;
case FLOAT_OP:
interpretFloatOp((AluInstr)instr, operation, context, floats, booleans, temp);
interpretFloatOp((AluInstr) instr, operation, floats, booleans);
break;
case ARG_OP:
receiveArg(context, instr, operation, args, acceptsKeywordArgument, currDynScope, temp, exception, block);
break;
case CALL_OP:
if (profile) Profiler.updateCallSite(instr, scope, scopeVersion);
//if (profile) Profiler.updateCallSite(instr, scope, scopeVersion);
processCall(context, instr, operation, currDynScope, currScope, temp, self);
break;
case RET_OP:
@@ -588,10 +570,13 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
break;
case BOOK_KEEPING_OP:
if (operation == Operation.PUSH_BINDING) {
currDynScope = getNewDynScope(context, scope, currScope);
// IMPORTANT: Preserve this update of currDynScope.
// This affects execution of all instructions in this scope
// which will now use the updated value of currDynScope.
currDynScope = interpreterContext.newDynamicScope(context);
context.pushScope(currDynScope);
} else {
processBookKeepingOp(context, instr, operation, name, args, self, block, implClass, visibility, temp, currDynScope);
processBookKeepingOp(context, instr, operation, name, args, self, block, implClass, visibility);
}
break;
case OTHER_OP:
@@ -601,7 +586,7 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
} catch (Throwable t) {
extractToMethodToAvoidC2Crash(context, instr, t);

if (debug) LOG.info("in scope: " + scope + ", caught Java throwable: " + t + "; excepting instr: " + instr);
if (debug) LOG.info("in : " + interpreterContext + ", caught Java throwable: " + t + "; excepting instr: " + instr);
ipc = instr.getRPC();
if (debug) LOG.info("ipc for rescuer: " + ipc);

Loading

0 comments on commit 572fdf9

Please sign in to comment.