package org.jruby.ir.interpreter;
import org.jruby.RubyBoolean;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyModule;
import org.jruby.exceptions.Unrescuable;
import org.jruby.ir.Operation;
import org.jruby.ir.instructions.BreakInstr;
import org.jruby.ir.instructions.CheckArityInstr;
import org.jruby.ir.instructions.CheckForLJEInstr;
import org.jruby.ir.instructions.CopyInstr;
import org.jruby.ir.instructions.Instr;
import org.jruby.ir.instructions.JumpInstr;
import org.jruby.ir.instructions.LineNumberInstr;
import org.jruby.ir.instructions.NonlocalReturnInstr;
import org.jruby.ir.instructions.PopBlockFrameInstr;
import org.jruby.ir.instructions.PushBlockFrameInstr;
import org.jruby.ir.instructions.PushMethodFrameInstr;
import org.jruby.ir.instructions.ReceiveArgBase;
import org.jruby.ir.instructions.ReceivePostReqdArgInstr;
import org.jruby.ir.instructions.ReceivePreReqdArgInstr;
import org.jruby.ir.instructions.RestoreBindingVisibilityInstr;
import org.jruby.ir.instructions.ResultInstr;
import org.jruby.ir.instructions.ReturnBase;
import org.jruby.ir.instructions.RuntimeHelperCall;
import org.jruby.ir.instructions.SaveBindingVisibilityInstr;
import org.jruby.ir.instructions.SearchConstInstr;
import org.jruby.ir.instructions.ToggleBacktraceInstr;
import org.jruby.ir.instructions.TraceInstr;
import org.jruby.ir.instructions.boxing.AluInstr;
import org.jruby.ir.instructions.boxing.BoxBooleanInstr;
import org.jruby.ir.instructions.boxing.BoxFixnumInstr;
import org.jruby.ir.instructions.boxing.BoxFloatInstr;
import org.jruby.ir.instructions.boxing.BoxInstr;
import org.jruby.ir.instructions.boxing.UnboxInstr;
import org.jruby.ir.instructions.specialized.OneFixnumArgNoBlockCallInstr;
import org.jruby.ir.instructions.specialized.OneFloatArgNoBlockCallInstr;
import org.jruby.ir.instructions.specialized.OneOperandArgBlockCallInstr;
import org.jruby.ir.instructions.specialized.OneOperandArgNoBlockCallInstr;
import org.jruby.ir.instructions.specialized.OneOperandArgNoBlockNoResultCallInstr;
import org.jruby.ir.instructions.specialized.TwoOperandArgNoBlockCallInstr;
import org.jruby.ir.instructions.specialized.ZeroOperandArgNoBlockCallInstr;
import org.jruby.ir.operands.Bignum;
import org.jruby.ir.operands.Fixnum;
import org.jruby.ir.operands.Float;
import org.jruby.ir.operands.LocalVariable;
import org.jruby.ir.operands.Operand;
import org.jruby.ir.operands.Self;
import org.jruby.ir.operands.TemporaryFixnumVariable;
import org.jruby.ir.operands.TemporaryFloatVariable;
import org.jruby.ir.operands.TemporaryLocalVariable;
import org.jruby.ir.operands.TemporaryVariable;
import org.jruby.ir.operands.UnboxedBoolean;
import org.jruby.ir.operands.UnboxedFixnum;
import org.jruby.ir.operands.UnboxedFloat;
import org.jruby.ir.operands.Variable;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Frame;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.ProfilingCachingCallSite;
import org.jruby.runtime.opto.ConstantCache;
public class InterpreterEngine {
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, Block blockArg) {
return interpret(context, block, self, interpreterContext, implClass, name, IRubyObject.NULL_ARRAY, blockArg);
}
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject arg1, Block blockArg) {
return interpret(context, block, self, interpreterContext, implClass, name, new IRubyObject[] {arg1}, blockArg);
}
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject arg1, IRubyObject arg2, Block blockArg) {
return interpret(context, block, self, interpreterContext, implClass, name, new IRubyObject[] {arg1, arg2}, blockArg);
}
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block blockArg) {
return interpret(context, block, self, interpreterContext, implClass, name, new IRubyObject[] {arg1, arg2, arg3}, blockArg);
}
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4, Block blockArg) {
return interpret(context, block, self, interpreterContext, implClass, name, new IRubyObject[] {arg1, arg2, arg3, arg4}, blockArg);
}
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject[] args, Block blockArg) {
Instr[] instrs = interpreterContext.getInstructions();
Object[] temp = interpreterContext.allocateTemporaryVariables();
double[] floats = interpreterContext.allocateTemporaryFloatVariables();
long[] fixnums = interpreterContext.allocateTemporaryFixnumVariables();
boolean[] booleans = interpreterContext.allocateTemporaryBooleanVariables();
int n = instrs.length;
int ipc = 0;
Object exception = null;
boolean acceptsKeywordArgument = interpreterContext.receivesKeywordArguments();
if (acceptsKeywordArgument) {
args = IRRuntimeHelpers.frobnicateKwargsArgument(context, args, interpreterContext.getRequiredArgsCount());
}
StaticScope currScope = interpreterContext.getStaticScope();
DynamicScope currDynScope = context.getCurrentScope();
boolean debug = IRRuntimeHelpers.isDebug();
boolean profile = IRRuntimeHelpers.inProfileMode();
Integer scopeVersion = profile ? Profiler.initProfiling(interpreterContext.getScope()) : 0;
while (ipc < n) {
Instr instr = instrs[ipc];
Operation operation = instr.getOperation();
if (debug) {
Interpreter.LOG.info("I: {" + ipc + "} " + instr);
Interpreter.interpInstrsCount++;
} else if (profile) {
Profiler.instrTick(operation);
Interpreter.interpInstrsCount++;
}
ipc++;
try {
switch (operation.opClass) {
case INT_OP:
interpretIntOp((AluInstr) instr, operation, fixnums, booleans);
break;
case FLOAT_OP:
interpretFloatOp((AluInstr) instr, operation, floats, booleans);
break;
case ARG_OP:
receiveArg(context, instr, operation, args, acceptsKeywordArgument, currDynScope, temp, exception, blockArg);
break;
case CALL_OP:
if (profile) Profiler.updateCallSite(instr, interpreterContext.getScope(), scopeVersion);
processCall(context, instr, operation, currDynScope, currScope, temp, self);
break;
case RET_OP:
return processReturnOp(context, block, instr, operation, currDynScope, temp, self, currScope);
case BRANCH_OP:
switch (operation) {
case JUMP: ipc = ((JumpInstr)instr).getJumpTarget().getTargetPC(); break;
default: ipc = instr.interpretAndGetNewIPC(context, currDynScope, currScope, self, temp, ipc); break;
}
break;
case BOOK_KEEPING_OP:
switch (operation) {
case PUSH_METHOD_BINDING:
currDynScope = interpreterContext.newDynamicScope(context);
context.pushScope(currDynScope);
break;
case PUSH_BLOCK_BINDING:
currDynScope = IRRuntimeHelpers.pushBlockDynamicScopeIfNeeded(context, block, interpreterContext.pushNewDynScope(), interpreterContext.reuseParentDynScope());
break;
case UPDATE_BLOCK_STATE:
self = IRRuntimeHelpers.updateBlockState(block, self);
break;
case PREPARE_NO_BLOCK_ARGS:
args = IRRuntimeHelpers.prepareNoBlockArgs(context, block, args);
break;
case PREPARE_SINGLE_BLOCK_ARG:
args = IRRuntimeHelpers.prepareSingleBlockArgs(context, block, args);
break;
case PREPARE_FIXED_BLOCK_ARGS:
args = IRRuntimeHelpers.prepareFixedBlockArgs(context, block, args);
break;
case PREPARE_BLOCK_ARGS:
args = IRRuntimeHelpers.prepareBlockArgs(context, block, args, acceptsKeywordArgument);
break;
default:
processBookKeepingOp(context, block, instr, operation, name, args, self, blockArg, implClass, currDynScope, temp, currScope);
break;
}
break;
case OTHER_OP:
processOtherOp(context, block, instr, operation, currDynScope, currScope, temp, self, floats, fixnums, booleans);
break;
}
} catch (Throwable t) {
if (debug) extractToMethodToAvoidC2Crash(instr, t);
ipc = ((FullInterpreterContext) interpreterContext).determineRPC(ipc);
if (debug) {
Interpreter.LOG.info("in : " + interpreterContext.getScope() + ", caught Java throwable: " + t + "; excepting instr: " + instr);
Interpreter.LOG.info("ipc for rescuer: " + ipc);
}
if (ipc == -1) {
Helpers.throwException(t);
} else {
exception = t;
}
}
}
throw context.runtime.newRuntimeError("BUG: interpreter fell through to end unexpectedly");
}
protected 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());
switch (op) {
case IADD: setFixnumVar(fixnums, dst, i1 + i2); break;
case ISUB: setFixnumVar(fixnums, dst, i1 - i2); break;
case IMUL: setFixnumVar(fixnums, dst, i1 * i2); break;
case IDIV: setFixnumVar(fixnums, dst, i1 / i2); break;
case IOR : setFixnumVar(fixnums, dst, i1 | i2); break;
case IAND: setFixnumVar(fixnums, dst, i1 & i2); break;
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(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);
}
}
protected 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());
switch (op) {
case FADD: setFloatVar(floats, dst, a1 + a2); break;
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(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);
}
}
protected static void receiveArg(ThreadContext context, Instr i, Operation operation, IRubyObject[] args, boolean acceptsKeywordArgument, DynamicScope currDynScope, Object[] temp, Object exception, Block blockArg) {
Object result;
ResultInstr instr = (ResultInstr)i;
switch(operation) {
case RECV_PRE_REQD_ARG:
int argIndex = ((ReceivePreReqdArgInstr)instr).getArgIndex();
result = IRRuntimeHelpers.getPreArgSafe(context, args, argIndex);
setResult(temp, currDynScope, instr.getResult(), result);
return;
case RECV_POST_REQD_ARG:
result = ((ReceivePostReqdArgInstr)instr).receivePostReqdArg(context, args, acceptsKeywordArgument);
setResult(temp, currDynScope, instr.getResult(), result);
return;
case RECV_RUBY_EXC:
setResult(temp, currDynScope, instr.getResult(), IRRuntimeHelpers.unwrapRubyException(exception));
return;
case RECV_JRUBY_EXC:
setResult(temp, currDynScope, instr.getResult(), exception);
return;
case LOAD_IMPLICIT_CLOSURE:
setResult(temp, currDynScope, instr.getResult(), blockArg);
return;
default:
result = ((ReceiveArgBase)instr).receiveArg(context, args, acceptsKeywordArgument);
setResult(temp, currDynScope, instr.getResult(), result);
}
}
protected static void processCall(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, StaticScope currScope, Object[] temp, IRubyObject self) {
Object result;
switch(operation) {
case CALL_1F: {
OneFixnumArgNoBlockCallInstr call = (OneFixnumArgNoBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
result = call.getCallSite().call(context, self, r, call.getFixnumArg());
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_1D: {
OneFloatArgNoBlockCallInstr call = (OneFloatArgNoBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
result = call.getCallSite().call(context, self, r, call.getFloatArg());
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_1O: {
OneOperandArgNoBlockCallInstr call = (OneOperandArgNoBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
result = call.getCallSite().call(context, self, r, o);
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_2O: {
TwoOperandArgNoBlockCallInstr call = (TwoOperandArgNoBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
IRubyObject o1 = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
IRubyObject o2 = (IRubyObject)call.getArg2().retrieve(context, self, currScope, currDynScope, temp);
result = call.getCallSite().call(context, self, r, o1, o2);
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_1OB: {
OneOperandArgBlockCallInstr call = (OneOperandArgBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
Block preparedBlock = call.prepareBlock(context, self, currScope, currDynScope, temp);
CallSite callSite = call.getCallSite();
result = call.hasLiteralClosure() ?
callSite.callIter(context, self, r, o, preparedBlock) :
callSite.call(context, self, r, o, preparedBlock);
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case CALL_0O: {
ZeroOperandArgNoBlockCallInstr call = (ZeroOperandArgNoBlockCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
result = call.getCallSite().call(context, self, r);
setResult(temp, currDynScope, call.getResult(), result);
break;
}
case NORESULT_CALL_1O: {
OneOperandArgNoBlockNoResultCallInstr call = (OneOperandArgNoBlockNoResultCallInstr)instr;
IRubyObject r = (IRubyObject)retrieveOp(call.getReceiver(), context, self, currDynScope, currScope, temp);
IRubyObject o = (IRubyObject)call.getArg1().retrieve(context, self, currScope, currDynScope, temp);
call.getCallSite().call(context, self, r, o);
break;
}
case NORESULT_CALL:
instr.interpret(context, currScope, currDynScope, self, temp);
break;
case CALL:
default:
result = instr.interpret(context, currScope, currDynScope, self, temp);
setResult(temp, currDynScope, instr, result);
break;
}
}
protected static void processBookKeepingOp(ThreadContext context, Block block, Instr instr, Operation operation,
String name, IRubyObject[] args, IRubyObject self, Block blockArg, RubyModule implClass,
DynamicScope currDynScope, Object[] temp, StaticScope currScope) {
switch(operation) {
case LABEL:
break;
case SAVE_BINDING_VIZ:
setResult(temp, currDynScope, ((SaveBindingVisibilityInstr) instr).getResult(), block.getBinding().getFrame().getVisibility());
break;
case RESTORE_BINDING_VIZ:
block.getBinding().getFrame().setVisibility((Visibility) retrieveOp(((RestoreBindingVisibilityInstr) instr).getVisibility(), context, self, currDynScope, currScope, temp));
break;
case PUSH_BLOCK_FRAME:
setResult(temp, currDynScope, ((PushBlockFrameInstr) instr).getResult(), context.preYieldNoScope(block.getBinding()));
break;
case POP_BLOCK_FRAME:
context.postYieldNoScope((Frame) retrieveOp(((PopBlockFrameInstr)instr).getFrame(), context, self, currDynScope, currScope, temp));
break;
case PUSH_METHOD_FRAME:
context.preMethodFrameOnly(
implClass,
name,
self,
((PushMethodFrameInstr) instr).getVisibility(),
blockArg);
break;
case PUSH_BACKREF_FRAME:
context.preBackrefMethod();
break;
case POP_METHOD_FRAME:
context.popFrame();
break;
case POP_BACKREF_FRAME:
context.postBackrefMethod();
break;
case POP_BINDING:
context.popScope();
break;
case THREAD_POLL:
if (IRRuntimeHelpers.inProfileMode()) Profiler.clockTick();
context.callThreadPoll();
break;
case CHECK_ARITY:
((CheckArityInstr) instr).checkArity(context, currScope, args, block);
break;
case LINE_NUM:
context.setLine(((LineNumberInstr)instr).lineNumber);
break;
case TOGGLE_BACKTRACE:
context.setExceptionRequiresBacktrace(((ToggleBacktraceInstr) instr).requiresBacktrace());
break;
case TRACE:
instr.interpret(context, currScope, currDynScope, self, temp);
break;
}
}
protected static IRubyObject processReturnOp(ThreadContext context, Block block, Instr instr, Operation operation,
DynamicScope currDynScope, Object[] temp, IRubyObject self,
StaticScope currScope) {
switch(operation) {
case RETURN: {
return (IRubyObject)retrieveOp(((ReturnBase)instr).getReturnValue(), context, self, currDynScope, currScope, temp);
}
case BREAK: {
BreakInstr bi = (BreakInstr)instr;
IRubyObject rv = (IRubyObject)bi.getReturnValue().retrieve(context, self, currScope, currDynScope, temp);
return IRRuntimeHelpers.initiateBreak(context, currDynScope, rv, block);
}
case NONLOCAL_RETURN: {
NonlocalReturnInstr ri = (NonlocalReturnInstr)instr;
IRubyObject rv = (IRubyObject)retrieveOp(ri.getReturnValue(), context, self, currDynScope, currScope, temp);
return IRRuntimeHelpers.initiateNonLocalReturn(currDynScope, block, rv);
}
case RETURN_OR_RETHROW_SAVED_EXC: {
IRubyObject retVal = (IRubyObject) retrieveOp(((ReturnBase) instr).getReturnValue(), context, self, currDynScope, currScope, temp);
return IRRuntimeHelpers.returnOrRethrowSavedException(context, retVal);
}
}
return null;
}
protected static void processOtherOp(ThreadContext context, Block block, Instr instr, Operation operation, DynamicScope currDynScope,
StaticScope currScope, Object[] temp, IRubyObject self,
double[] floats, long[] fixnums, boolean[] booleans) {
Object result;
switch(operation) {
case RECV_SELF:
break;
case COPY: {
CopyInstr c = (CopyInstr)instr;
Operand src = c.getSource();
Variable res = c.getResult();
if (res instanceof TemporaryFloatVariable) {
setFloatVar(floats, (TemporaryFloatVariable)res, getFloatArg(floats, src));
} else if (res instanceof TemporaryFixnumVariable) {
setFixnumVar(fixnums, (TemporaryFixnumVariable)res, getFixnumArg(fixnums, src));
} else {
setResult(temp, currDynScope, res, retrieveOp(src, context, self, currDynScope, currScope, temp));
}
break;
}
case SEARCH_CONST: {
SearchConstInstr sci = (SearchConstInstr)instr;
ConstantCache cache = sci.getConstantCache();
if (!ConstantCache.isCached(cache)) {
result = sci.cache(context, currScope, currDynScope, self, temp);
} else {
result = cache.value;
}
setResult(temp, currDynScope, sci.getResult(), result);
break;
}
case RUNTIME_HELPER: {
RuntimeHelperCall rhc = (RuntimeHelperCall)instr;
setResult(temp, currDynScope, rhc.getResult(),
rhc.callHelper(context, currScope, currDynScope, self, temp, block));
break;
}
case CHECK_FOR_LJE:
((CheckForLJEInstr) instr).check(context, currDynScope, block);
break;
case BOX_FLOAT: {
RubyFloat f = context.runtime.newFloat(getFloatArg(floats, ((BoxFloatInstr)instr).getValue()));
setResult(temp, currDynScope, ((BoxInstr)instr).getResult(), f);
break;
}
case BOX_FIXNUM: {
RubyFixnum f = context.runtime.newFixnum(getFixnumArg(fixnums, ((BoxFixnumInstr) instr).getValue()));
setResult(temp, currDynScope, ((BoxInstr)instr).getResult(), f);
break;
}
case BOX_BOOLEAN: {
RubyBoolean f = context.runtime.newBoolean(getBooleanArg(booleans, ((BoxBooleanInstr) instr).getValue()));
setResult(temp, currDynScope, ((BoxInstr)instr).getResult(), f);
break;
}
case UNBOX_FLOAT: {
UnboxInstr ui = (UnboxInstr)instr;
Object val = retrieveOp(ui.getValue(), context, self, currDynScope, currScope, temp);
if (val instanceof RubyFloat) {
floats[((TemporaryLocalVariable)ui.getResult()).offset] = ((RubyFloat)val).getValue();
} else {
floats[((TemporaryLocalVariable)ui.getResult()).offset] = ((RubyFixnum)val).getDoubleValue();
}
break;
}
case UNBOX_FIXNUM: {
UnboxInstr ui = (UnboxInstr)instr;
Object val = retrieveOp(ui.getValue(), context, self, currDynScope, currScope, temp);
if (val instanceof RubyFloat) {
fixnums[((TemporaryLocalVariable)ui.getResult()).offset] = ((RubyFloat)val).getLongValue();
} else {
fixnums[((TemporaryLocalVariable)ui.getResult()).offset] = ((RubyFixnum)val).getLongValue();
}
break;
}
case LOAD_FRAME_CLOSURE:
setResult(temp, currDynScope, instr, context.getFrameBlock());
return;
default:
result = instr.interpret(context, currScope, currDynScope, self, temp);
setResult(temp, currDynScope, instr, result);
break;
}
}
protected static void (Instr instr, Throwable t) {
if (!(t instanceof Unrescuable) && !instr.canRaiseException()) {
System.err.println("BUG: Got exception " + t + " but instr " + instr + " is not supposed to be raising exceptions!");
}
}
protected static void setResult(Object[] temp, DynamicScope currDynScope, Variable resultVar, Object result) {
if (resultVar instanceof TemporaryVariable) {
temp[((TemporaryLocalVariable)resultVar).offset] = result;
} else {
LocalVariable lv = (LocalVariable)resultVar;
currDynScope.setValueVoid((IRubyObject) result, lv.getLocation(), lv.getScopeDepth());
}
}
protected static void setResult(Object[] temp, DynamicScope currDynScope, Instr instr, Object result) {
if (instr instanceof ResultInstr) {
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), result);
}
}
protected static Object retrieveOp(Operand r, ThreadContext context, IRubyObject self, DynamicScope currDynScope, StaticScope currScope, Object[] temp) {
Object res;
if (r instanceof Self) {
return self;
} else if (r instanceof TemporaryLocalVariable) {
res = temp[((TemporaryLocalVariable)r).offset];
return res == null ? context.nil : res;
} else if (r instanceof LocalVariable) {
LocalVariable lv = (LocalVariable)r;
res = currDynScope.getValue(lv.getLocation(), lv.getScopeDepth());
return res == null ? context.nil : res;
} else {
return r.retrieve(context, self, currScope, currDynScope, temp);
}
}
private static double getFloatArg(double[] floats, Operand arg) {
if (arg instanceof Float) {
return ((Float)arg).value;
} else if (arg instanceof UnboxedFloat) {
return ((UnboxedFloat)arg).value;
} else if (arg instanceof Fixnum) {
return (double)((Fixnum)arg).value;
} else if (arg instanceof UnboxedFixnum) {
return (double)((UnboxedFixnum)arg).value;
} else if (arg instanceof Bignum) {
return ((Bignum)arg).value.doubleValue();
} else if (arg instanceof TemporaryLocalVariable) {
return floats[((TemporaryLocalVariable)arg).offset];
} else {
throw new RuntimeException("invalid float operand: " + arg);
}
}
private static long getFixnumArg(long[] fixnums, Operand arg) {
if (arg instanceof Float) {
return (long)((Float)arg).value;
} else if (arg instanceof UnboxedFixnum) {
return ((UnboxedFixnum)arg).value;
} else if (arg instanceof Fixnum) {
return ((Fixnum)arg).value;
} else if (arg instanceof Bignum) {
return ((Bignum)arg).value.longValue();
} else if (arg instanceof TemporaryLocalVariable) {
return fixnums[((TemporaryLocalVariable)arg).offset];
} else {
throw new RuntimeException("invalid fixnum operand: " + arg);
}
}
private static boolean getBooleanArg(boolean[] booleans, Operand arg) {
if (arg instanceof UnboxedBoolean) {
return ((UnboxedBoolean)arg).isTrue();
} else if (arg instanceof TemporaryLocalVariable) {
return booleans[((TemporaryLocalVariable)arg).offset];
} else {
throw new RuntimeException("invalid fixnum operand: " + arg);
}
}
private static void setFloatVar(double[] floats, TemporaryLocalVariable var, double val) {
floats[var.offset] = val;
}
private static void setFixnumVar(long[] fixnums, TemporaryLocalVariable var, long val) {
fixnums[var.offset] = val;
}
private static void setBooleanVar(boolean[] booleans, TemporaryLocalVariable var, boolean val) {
booleans[var.offset] = val;
}
}