Skip to content

Commit

Permalink
Always add call protocol instructions in interpreter mode.
Browse files Browse the repository at this point in the history
* Some benchmarks are marginally faster and others slower.
  Overall, somewhat slower. But, runtime code is simpler.
  So, we are going for this right now.
  • Loading branch information
subbuss committed Oct 23, 2014
1 parent 67f4a90 commit f2350bf
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 90 deletions.
Expand Up @@ -5,8 +5,9 @@

import org.jruby.RubyModule;
import org.jruby.ir.*;
import org.jruby.ir.interpreter.Interpreter;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.parser.StaticScope;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
Expand All @@ -22,7 +23,6 @@ public List<String[]> getParameterList() {
return new ArrayList<String[]>();
}

@Override
protected void post(InterpreterContext ic, ThreadContext context) {
// update call stacks (pop: ..)
context.popFrame();
Expand All @@ -31,7 +31,6 @@ protected void post(InterpreterContext ic, ThreadContext context) {
}
}

@Override
protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject self, String name, Block block) {
// update call stacks (push: frame, class, scope, etc.)
context.preMethodFrameOnly(getImplementationClass(), name, self, block);
Expand All @@ -44,6 +43,30 @@ protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject sel
context.setCurrentVisibility(getVisibility());
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
DynamicMethodBox box = this.box;
if (box.callCount >= 0) tryJit(context, box);
DynamicMethod actualMethod = box.actualMethod;
if (actualMethod != null) return actualMethod.call(context, self, clazz, name, args, block);

InterpreterContext ic = ensureInstrsReady();

if (IRRuntimeHelpers.isDebug()) doDebug();

if (ic.hasExplicitCallProtocol()) {
return Interpreter.INTERPRET_METHOD(context, this, self, name, args, block);
} else {
try {
pre(ic, context, self, name, block);

return Interpreter.INTERPRET_METHOD(context, this, self, name, args, block);
} finally {
post(ic, context);
}
}
}

@Override
public DynamicMethod dup() {
InterpretedIRMetaClassBody x = new InterpretedIRMetaClassBody(method, implementationClass);
Expand Down
Expand Up @@ -39,12 +39,12 @@ public class InterpretedIRMethod extends DynamicMethod implements IRMethodArgs,
// our backtraces.
private boolean isSynthetic;

private static class DynamicMethodBox {
protected static class DynamicMethodBox {
public DynamicMethod actualMethod;
public int callCount = 0;
}

private DynamicMethodBox box = new DynamicMethodBox();
protected DynamicMethodBox box = new DynamicMethodBox();

public InterpretedIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
super(implementationClass, visibility, CallConfiguration.FrameNoneScopeNone, method.getName());
Expand Down Expand Up @@ -93,6 +93,13 @@ public Arity getArity() {
return this.arity;
}

public InterpreterContext ensureInstrsReady() {
// Try unsync access first before calling more expensive method for getting IC
InterpreterContext ic = method.getInterpreterContext();

return ic == null ? method.prepareForInterpretation() : ic;
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
DynamicMethodBox box = this.box;
Expand All @@ -104,17 +111,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

if (IRRuntimeHelpers.isDebug()) doDebug();

if (ic.hasExplicitCallProtocol()) {
return Interpreter.INTERPRET_METHOD(context, this, self, name, args, block);
} else {
try {
pre(ic, context, self, name, block);

return Interpreter.INTERPRET_METHOD(context, this, self, name, args, block);
} finally {
post(ic, context);
}
}
return Interpreter.INTERPRET_METHOD(context, this, self, name, args, block);
}

@Override
Expand All @@ -128,17 +125,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

if (IRRuntimeHelpers.isDebug()) doDebug();

if (ic.hasExplicitCallProtocol()) {
return Interpreter.INTERPRET_METHOD(context, this, self, name, IRubyObject.NULL_ARRAY, block);
} else {
try {
pre(ic, context, self, name, block);

return Interpreter.INTERPRET_METHOD(context, this, self, name, IRubyObject.NULL_ARRAY, block);
} finally {
post(ic, context);
}
}
return Interpreter.INTERPRET_METHOD(context, this, self, name, IRubyObject.NULL_ARRAY, block);
}

@Override
Expand All @@ -152,17 +139,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

if (IRRuntimeHelpers.isDebug()) doDebug();

if (ic.hasExplicitCallProtocol()) {
return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0), block);
} else {
try {
pre(ic, context, self, name, block);

return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0), block);
} finally {
post(ic, context);
}
}
return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0), block);
}

@Override
Expand All @@ -176,17 +153,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

if (IRRuntimeHelpers.isDebug()) doDebug();

if (ic.hasExplicitCallProtocol()) {
return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0, arg1), block);
} else {
try {
pre(ic, context, self, name, block);

return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0, arg1), block);
} finally {
post(ic, context);
}
}
return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0, arg1), block);
}

@Override
Expand All @@ -200,17 +167,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

if (IRRuntimeHelpers.isDebug()) doDebug();

if (ic.hasExplicitCallProtocol()) {
return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0, arg1, arg2), block);
} else {
try {
pre(ic, context, self, name, block);

return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0, arg1, arg2), block);
} finally {
post(ic, context);
}
}
return Interpreter.INTERPRET_METHOD(context, this, self, name, Helpers.arrayOf(arg0, arg1, arg2), block);
}

protected void doDebug() {
Expand All @@ -225,30 +182,6 @@ protected void doDebug() {
}
}

protected void post(InterpreterContext ic, ThreadContext context) {
// update call stacks (pop: ..)
context.popFrame();
if (ic.popDynScope()) {
context.popScope();
}
}

protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject self, String name, Block block) {
// update call stacks (push: frame, class, scope, etc.)
context.preMethodFrameOnly(getImplementationClass(), name, self, block);
if (ic.pushNewDynScope()) {
context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope()));
}
context.setCurrentVisibility(getVisibility());
}

public InterpreterContext ensureInstrsReady() {
// Try unsync access first before calling more expensive method for getting IC
InterpreterContext ic = method.getInterpreterContext();

return ic == null ? method.prepareForInterpretation() : ic;
}

public DynamicMethod getMethodForCaching() {
DynamicMethod method = box.actualMethod;
if (method instanceof CompiledIRMethod) {
Expand All @@ -265,7 +198,7 @@ public void switchToJitted(CompiledIRMethod newMethod) {
}


private void tryJit(ThreadContext context, DynamicMethodBox box) {
protected void tryJit(ThreadContext context, DynamicMethodBox box) {
Ruby runtime = context.runtime;

// don't JIT during runtime boot
Expand Down
13 changes: 8 additions & 5 deletions core/src/main/java/org/jruby/ir/IRScope.java
Expand Up @@ -9,11 +9,7 @@
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.operands.*;
import org.jruby.ir.operands.Float;
import org.jruby.ir.passes.CompilerPass;
import org.jruby.ir.passes.CompilerPassScheduler;
import org.jruby.ir.passes.DeadCodeElimination;
import org.jruby.ir.passes.OptimizeDynScopesPass;
import org.jruby.ir.passes.UnboxingPass;
import org.jruby.ir.passes.*;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.representations.BasicBlock;
import org.jruby.ir.representations.CFG;
Expand Down Expand Up @@ -627,6 +623,13 @@ public synchronized InterpreterContext prepareForInterpretation() {

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

// Always add call protocol instructions now for both interpreter and JIT
// since we are removing support for implicit stuff in the interpreter.
// When JIT later runs this same pass, it will be a NOP there.
if (!isUnsafeScope()) {
(new AddCallProtocolInstructions()).run(this);
}

interpreterContext = allocateInterpreterContext(prepareInstructions());

return interpreterContext;
Expand Down

0 comments on commit f2350bf

Please sign in to comment.