InterpreterContext.java
package org.jruby.ir.interpreter;
import org.jruby.ir.IRFlags;
import org.jruby.ir.IRMetaClassBody;
import org.jruby.ir.IRScope;
import org.jruby.ir.instructions.Instr;
import org.jruby.ir.representations.CFG;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
public class InterpreterContext {
private final int temporaryVariablecount;
private final int temporaryBooleanVariablecount;
private final int temporaryFixnumVariablecount;
private final int temporaryFloatVariablecount;
private final String name;
private final String fileName;
private final int lineNumber;
private final StaticScope staticScope;
private final Instr[] instructions;
// Cached computed fields
private final boolean hasExplicitCallProtocol;
private final boolean isDynscopeEliminated;
private final boolean pushNewDynScope;
private final boolean reuseParentDynScope;
private final boolean popDynScope;
private final boolean receivesKeywordArguments;
private final boolean metaClassBodyScope;
// FIXME: Hack this should be a clone eventually since JIT might change this. Comment for it reflects what it should be.
// View of CFG at time of creating this context.
private CFG cfg = null;
public InterpreterContext(IRScope scope, Instr[] instructions) {
//FIXME: Remove once we conditionally plug in CFG on debug-only
this.cfg = scope.getCFG();
this.name = scope.getName();
this.fileName = scope.getFileName();
this.lineNumber = scope.getLineNumber();
this.staticScope = scope.getStaticScope();
this.metaClassBodyScope = scope instanceof IRMetaClassBody;
this.temporaryVariablecount = scope.getTemporaryVariablesCount();
this.temporaryBooleanVariablecount = scope.getBooleanVariablesCount();
this.temporaryFixnumVariablecount = scope.getFixnumVariablesCount();
this.temporaryFloatVariablecount = scope.getFloatVariablesCount();
this.instructions = instructions;
this.hasExplicitCallProtocol = scope.getFlags().contains(IRFlags.HAS_EXPLICIT_CALL_PROTOCOL);
this.reuseParentDynScope = scope.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE);
this.isDynscopeEliminated = scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);
this.pushNewDynScope = !isDynscopeEliminated && !reuseParentDynScope;
this.popDynScope = this.pushNewDynScope || this.reuseParentDynScope;
this.receivesKeywordArguments = scope.getFlags().contains(IRFlags.RECEIVES_KEYWORD_ARGS);
}
public Object[] allocateTemporaryVariables() {
return temporaryVariablecount > 0 ? new Object[temporaryVariablecount] : null;
}
public boolean[] allocateTemporaryBooleanVariables() {
return temporaryBooleanVariablecount > 0 ? new boolean[temporaryBooleanVariablecount] : null;
}
public long[] allocateTemporaryFixnumVariables() {
return temporaryFixnumVariablecount > 0 ? new long[temporaryFixnumVariablecount] : null;
}
public double[] allocateTemporaryFloatVariables() {
return temporaryFloatVariablecount > 0 ? new double[temporaryFloatVariablecount] : null;
}
public String getFileName() {
return fileName;
}
public StaticScope getStaticScope() {
return staticScope;
}
public int getTemporaryVariablecount() {
return temporaryVariablecount;
}
public int getTemporaryBooleanVariablecount() {
return temporaryBooleanVariablecount;
}
public int getTemporaryFixnumVariablecount() {
return temporaryFixnumVariablecount;
}
public int getTemporaryFloatVariablecount() {
return temporaryFloatVariablecount;
}
public Instr[] getInstructions() {
return instructions;
}
public boolean isDynscopeEliminated() {
return isDynscopeEliminated;
}
/**
* Get a new dynamic scope. Note: This only works for method scopes (ClosureIC will throw).
*/
public DynamicScope newDynamicScope(ThreadContext context) {
// 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.
if (metaClassBodyScope) return DynamicScope.newDynamicScope(staticScope, context.getCurrentScope());
return DynamicScope.newDynamicScope(staticScope);
}
public boolean hasExplicitCallProtocol() {
return hasExplicitCallProtocol;
}
public boolean pushNewDynScope() {
return pushNewDynScope;
}
public boolean reuseParentDynScope() {
return reuseParentDynScope;
}
public boolean popDynScope() {
return popDynScope;
}
public boolean receivesKeywordArguments() {
return receivesKeywordArguments;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(fileName).append(':').append(lineNumber);
if (name != null) buf.append(' ').append(name);
buf.append("\nCFG:\n").append(cfg.toStringInstrs());
return buf.toString();
}
}