package org.jruby.internal.runtime.methods;
import java.io.ByteArrayOutputStream;
import org.jruby.RubyModule;
import org.jruby.compiler.Compilable;
import org.jruby.internal.runtime.AbstractIRMethod;
import org.jruby.ir.IRScope;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.persistence.IRDumper;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
public class InterpretedIRMethod extends AbstractIRMethod implements Compilable<InterpreterContext> {
private static final Logger LOG = LoggerFactory.getLogger(InterpretedIRMethod.class);
private boolean displayedCFG = false;
public InterpretedIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
super(method, visibility, implementationClass);
if (implementationClass.getRuntime().getInstanceConfig().getJitThreshold() == -1) setCallCount(-1);
method.compilable = this;
}
protected void post(InterpreterContext ic, ThreadContext context) {
context.popFrame();
if (ic.popDynScope()) {
context.popScope();
}
}
protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject self, String name, Block block, RubyModule implClass) {
context.preMethodFrameOnly(implClass, name, self, block);
if (ic.pushNewDynScope()) {
context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope()));
}
}
@Override
protected void printMethodIR() {
ByteArrayOutputStream baos = IRDumper.printIR(method, false, true);
LOG.info("Printing simple IR for " + method.getId() + ":\n" + new String(baos.toByteArray()));
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, args, block);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, args, Block.NULL_BLOCK);
}
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
IRubyObject self, String name, IRubyObject[] args, Block block) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
if (ic.hasExplicitCallProtocol()) {
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
} else {
try {
pre(ic, context, self, name, block, implClass);
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
} finally {
post(ic, context);
}
}
} finally {
ThreadContext.popBacktrace(context);
}
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, block);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, Block.NULL_BLOCK);
}
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
IRubyObject self, String name, Block block) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
if (ic.hasExplicitCallProtocol()) {
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
} else {
try {
pre(ic, context, self, name, block, implClass);
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
} finally {
post(ic, context);
}
}
} finally {
ThreadContext.popBacktrace(context);
}
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, arg0, block);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, arg0, Block.NULL_BLOCK);
}
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
IRubyObject self, String name, IRubyObject arg1, Block block) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
if (ic.hasExplicitCallProtocol()) {
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
} else {
try {
pre(ic, context, self, name, block, implClass);
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
} finally {
post(ic, context);
}
}
} finally {
ThreadContext.popBacktrace(context);
}
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, arg0, arg1, block);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, arg0, arg1, Block.NULL_BLOCK);
}
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, Block block) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
if (ic.hasExplicitCallProtocol()) {
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
} else {
try {
pre(ic, context, self, name, block, implClass);
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
} finally {
post(ic, context);
}
}
} finally {
ThreadContext.popBacktrace(context);
}
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, arg0, arg1, arg2, block);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
if (IRRuntimeHelpers.isDebug()) doDebug();
if (callCount >= 0) promoteToFullBuild(context);
return INTERPRET_METHOD(context, ensureInstrsReady(), clazz, self, name, arg0, arg1, arg2, Block.NULL_BLOCK);
}
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
if (ic.hasExplicitCallProtocol()) {
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
} else {
try {
pre(ic, context, self, name, block, implClass);
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
} finally {
post(ic, context);
}
}
} finally {
ThreadContext.popBacktrace(context);
}
}
protected void doDebug() {
ensureInstrsReady();
LOG.info("Executing '" + method.getId() + "'");
if (!displayedCFG) {
LOG.info(method.debugOutput());
displayedCFG = true;
}
}
public void completeBuild(InterpreterContext interpreterContext) {
this.interpreterContext = interpreterContext;
this.displayedCFG = false;
}
private void promoteToFullBuild(ThreadContext context) {
tryJit(context, this);
if (IRRuntimeHelpers.shouldPrintIR(context.runtime)) {
ByteArrayOutputStream baos = IRDumper.printIR(method, true, true);
LOG.info("Printing full IR for " + method.getId() + ":\n" + new String(baos.toByteArray()));
}
}
public String getClassName(ThreadContext context) {
return null;
}
}