
org.jruby.ir.interpreter.BodyInterpreterEngine Maven / Gradle / Ivy
package org.jruby.ir.interpreter;
import org.jruby.RubyModule;
import org.jruby.common.IRubyWarnings;
import org.jruby.ir.OpClass;
import org.jruby.ir.Operation;
import org.jruby.ir.instructions.CopyInstr;
import org.jruby.ir.instructions.GetFieldInstr;
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.ResultInstr;
import org.jruby.ir.instructions.ReturnBase;
import org.jruby.ir.instructions.RuntimeHelperCall;
import org.jruby.ir.instructions.SearchConstInstr;
import org.jruby.ir.instructions.specialized.OneOperandArgNoBlockCallInstr;
import org.jruby.ir.instructions.specialized.OneOperandArgNoBlockNoResultCallInstr;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
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.ivars.VariableAccessor;
import org.jruby.runtime.opto.ConstantCache;
/**
* An interpreter which puts common subset of instrs in main switch.
*/
public class BodyInterpreterEngine extends InterpreterEngine {
@Override
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self, InterpreterContext interpreterContext, RubyModule implClass, String name, Block blockArg) {
Instr[] instrs = interpreterContext.getInstructions();
Object[] temp = interpreterContext.allocateTemporaryVariables();
int n = instrs.length;
int ipc = 0;
Object exception = null;
StaticScope currScope = interpreterContext.getStaticScope();
DynamicScope currDynScope = context.getCurrentScope();
Block.Type blockType = block == null ? null : block.type;
// Init profiling this scope
boolean debug = IRRuntimeHelpers.isDebug();
// Enter the looooop!
while (ipc < n) {
Instr instr = instrs[ipc];
Operation operation = instr.getOperation();
if (debug) {
Interpreter.LOG.info("I: {" + ipc + "} ", instr);
Interpreter.interpInstrsCount++;
}
ipc++;
try {
Frame f;
switch (operation) {
case RETURN:
return (IRubyObject) retrieveOp(((ReturnBase) instr).getReturnValue(), context, self, currDynScope, currScope, temp);
case NONLOCAL_RETURN: {
NonlocalReturnInstr ri = (NonlocalReturnInstr)instr;
IRubyObject rv = (IRubyObject)retrieveOp(ri.getReturnValue(), context, self, currDynScope, currScope, temp);
return IRRuntimeHelpers.initiateNonLocalReturn(context, currDynScope, blockType, rv);
}
case LINE_NUM:
context.setLine(((LineNumberInstr) instr).lineNumber);
break;
case RECV_SELF:
break;
case RECV_JRUBY_EXC:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), exception);
break;
case THROW:
instr.interpret(context, currScope, currDynScope, self, temp);
break;
case PUSH_BLOCK_FRAME:
f = context.preYieldNoScope(block.getBinding());
setResult(temp, currDynScope, ((PushBlockFrameInstr)instr).getResult(), f);
break;
case POP_BLOCK_FRAME:
f = (Frame)retrieveOp(((PopBlockFrameInstr)instr).getFrame(), context, self, currDynScope, currScope, temp);
context.postYieldNoScope(f);
break;
case PUSH_METHOD_FRAME:
context.preMethodFrameOnly(implClass, name, self, blockArg);
// Only the top-level script scope has PRIVATE visibility.
// This is already handled as part of Interpreter.execute above.
// Everything else is PUBLIC by default.
context.setCurrentVisibility(Visibility.PUBLIC);
break;
case POP_METHOD_FRAME:
context.popFrame();
break;
case PUSH_METHOD_BINDING:
// 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);
break;
case POP_BINDING:
context.popScope();
break;
case LOAD_FRAME_CLOSURE:
setResult(temp, currDynScope, instr, context.getFrameBlock());
break;
case DEF_INST_METH:
instr.interpret(context, currScope, currDynScope, self, temp);
break;
case PUT_CONST:
instr.interpret(context, currScope, currDynScope, self, temp);
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 SEARCH_CONST: {
SearchConstInstr sci = (SearchConstInstr) instr;
ConstantCache cache = sci.getConstantCache();
Object result;
if (!ConstantCache.isCached(cache)) {
result = sci.cache(context, currScope, currDynScope, self, temp);
} else {
result = cache.value;
}
setResult(temp, currDynScope, sci.getResult(), result);
break;
}
case PROCESS_MODULE_BODY:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(),
instr.interpret(context, currScope, currDynScope, self, temp));
break;
case DEF_CLASS:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(),
instr.interpret(context, currScope, currDynScope, self, temp));
break;
case INHERITANCE_SEARCH_CONST:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(),
instr.interpret(context, currScope, currDynScope, self, temp));
break;
case DEF_MODULE:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(),
instr.interpret(context, currScope, currDynScope, self, temp));
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);
setResult(temp, currDynScope, call.getResult(), call.getCallSite().call(context, self, r, o));
break;
}
case BNE:
ipc = instr.interpretAndGetNewIPC(context, currDynScope, currScope, self, temp, ipc);
break;
case DEF_CLASS_METH:
instr.interpret(context, currScope, currDynScope, self, temp);
break;
case LOAD_IMPLICIT_CLOSURE:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), blockArg);
break;
case RECV_RUBY_EXC: // NO INTERP
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), IRRuntimeHelpers.unwrapRubyException(exception));
break;
case COPY: // NO INTERP
setResult(temp, currDynScope, ((CopyInstr) instr).getResult(),
retrieveOp(((CopyInstr) instr).getSource(), context, self, currDynScope, currScope, temp));
break;
case JUMP: // NO INTERP
ipc = ((JumpInstr)instr).getJumpTarget().getTargetPC();
break;
case RUNTIME_HELPER: { // NO INTERP
RuntimeHelperCall rhc = (RuntimeHelperCall)instr;
setResult(temp, currDynScope, rhc.getResult(),
rhc.callHelper(context, currScope, currDynScope, self, temp, blockType));
break;
}
case GET_FIELD: { // NO INTERP
GetFieldInstr gfi = (GetFieldInstr)instr;
IRubyObject object = (IRubyObject)gfi.getSource().retrieve(context, self, currScope, currDynScope, temp);
VariableAccessor a = gfi.getAccessor(object);
Object result = a == null ? null : (IRubyObject)a.get(object);
if (result == null) {
if (context.runtime.isVerbose()) {
context.runtime.getWarnings().warning(IRubyWarnings.ID.IVAR_NOT_INITIALIZED, "instance variable " + gfi.getRef() + " not initialized");
}
result = context.nil;
}
setResult(temp, currDynScope, gfi.getResult(), result);
break;
}
default:
if (instr.getOperation().opClass == OpClass.BRANCH_OP) {
ipc = instr.interpretAndGetNewIPC(context, currDynScope, currScope, self, temp, ipc);
} else {
Object result = instr.interpret(context, currScope, currDynScope, self, temp);
setResult(temp, currDynScope, instr, result);
}
}
} catch (Throwable t) {
ipc = instr.getRPC();
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");
}
@Override
public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self, InterpreterContext interpreterContext, RubyModule implClass, String name, IRubyObject[] args, Block blockArg) {
return interpret(context, block, self, interpreterContext, implClass, name, blockArg);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy