Skip to content

Commit b1b1644

Browse files
committedMar 22, 2018
Restructure JIT to happen in one place each for methods and blocks
This introduces a third method and block top, the "OptInterpreter" version. All methods and blocks in a normal run are MixedMode now, aggregating both an Interpreted and a slot for an optimized or jitted version. This commit also simplifies some call paths in the IR block bodies and lowers several methods into CompiledIRBlockBody to be more direct.
1 parent 6902809 commit b1b1644

19 files changed

+491
-636
lines changed
 

Diff for: ‎core/src/main/java/org/jruby/RubyModule.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
import org.jruby.runtime.CallSite;
9393
import org.jruby.runtime.ClassIndex;
9494
import org.jruby.runtime.Helpers;
95-
import org.jruby.runtime.IRBlockBody;
95+
import org.jruby.runtime.AbstractIRBlockBody;
9696
import org.jruby.runtime.MethodFactory;
9797
import org.jruby.runtime.MethodIndex;
9898
import org.jruby.runtime.ObjectAllocator;
@@ -105,7 +105,6 @@
105105
import org.jruby.runtime.ivars.MethodData;
106106
import org.jruby.runtime.marshal.MarshalStream;
107107
import org.jruby.runtime.marshal.UnmarshalStream;
108-
import org.jruby.runtime.opto.ConstantInvalidator;
109108
import org.jruby.runtime.opto.Invalidator;
110109
import org.jruby.runtime.opto.OptoFactory;
111110
import org.jruby.runtime.profile.MethodEnhancer;
@@ -1991,9 +1990,9 @@ public IRubyObject defineMethodFromBlock(ThreadContext context, IRubyObject arg0
19911990

19921991
// If we know it comes from IR we can convert this directly to a method and
19931992
// avoid overhead of invoking it as a block
1994-
if (block.getBody() instanceof IRBlockBody &&
1993+
if (block.getBody() instanceof AbstractIRBlockBody &&
19951994
runtime.getInstanceConfig().getCompileMode().shouldJIT()) { // FIXME: Once Interp and Mixed Methods are one class we can fix this to work in interp mode too.
1996-
IRBlockBody body = (IRBlockBody) block.getBody();
1995+
AbstractIRBlockBody body = (AbstractIRBlockBody) block.getBody();
19971996
IRClosure closure = body.getScope();
19981997

19991998
// Ask closure to give us a method equivalent.

Diff for: ‎core/src/main/java/org/jruby/compiler/FullBuildTask.java renamed to ‎core/src/main/java/org/jruby/compiler/BlockFullBuildTask.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
package org.jruby.compiler;
22

3-
import org.jruby.ir.interpreter.InterpreterContext;
3+
import org.jruby.runtime.MixedModeIRBlockBody;
4+
import org.jruby.runtime.OptInterpretedIRBlockBody;
45

56
/**
67
* Created by headius on 12/8/16.
78
*/
8-
class FullBuildTask implements Runnable {
9+
class BlockFullBuildTask implements Runnable {
910
private JITCompiler jitCompiler;
10-
private final Compilable<InterpreterContext> method;
11+
private final MixedModeIRBlockBody method;
1112

12-
FullBuildTask(JITCompiler jitCompiler, Compilable<InterpreterContext> method) {
13+
BlockFullBuildTask(JITCompiler jitCompiler, MixedModeIRBlockBody method) {
1314
this.jitCompiler = jitCompiler;
1415
this.method = method;
1516
}
1617

1718
public void run() {
1819
try {
19-
method.getIRScope().getRootLexicalScope().prepareFullBuild();
20-
21-
method.completeBuild(method.getIRScope().prepareFullBuild());
20+
method.completeBuild(new OptInterpretedIRBlockBody(method.getScope(), method.getSignature()));
2221

2322
if (jitCompiler.config.isJitLogging()) {
2423
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), method.getName(), "done building");

Diff for: ‎core/src/main/java/org/jruby/compiler/JITCompiler.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,23 @@ public void tearDown() {
146146
}
147147

148148
public Runnable getTaskFor(ThreadContext context, Compilable method) {
149+
boolean shouldJit = context.runtime.getInstanceConfig().getCompileMode().shouldJIT();
150+
149151
if (method instanceof MixedModeIRMethod) {
150-
return new MethodJITTask(this, (MixedModeIRMethod) method, method.getClassName(context));
152+
if (shouldJit) {
153+
return new MethodJITTask(this, (MixedModeIRMethod) method, method.getClassName(context));
154+
} else {
155+
return new MethodFullBuildTask(this, (MixedModeIRMethod) method);
156+
}
151157
} else if (method instanceof MixedModeIRBlockBody) {
152-
return new BlockJITTask(this, (MixedModeIRBlockBody) method, method.getClassName(context));
158+
if (shouldJit) {
159+
return new BlockJITTask(this, (MixedModeIRBlockBody) method, method.getClassName(context));
160+
} else {
161+
return new BlockFullBuildTask(this, (MixedModeIRBlockBody) method);
162+
}
153163
}
154164

155-
return new FullBuildTask(this, method);
165+
throw new RuntimeException("unknown method type for JIT: " + method);
156166
}
157167

158168
public void buildThresholdReached(ThreadContext context, final Compilable method) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.jruby.compiler;
2+
3+
import org.jruby.internal.runtime.methods.MixedModeIRMethod;
4+
import org.jruby.internal.runtime.methods.OptInterpretedIRMethod;
5+
import org.jruby.runtime.MixedModeIRBlockBody;
6+
import org.jruby.runtime.OptInterpretedIRBlockBody;
7+
8+
class MethodFullBuildTask implements Runnable {
9+
private JITCompiler jitCompiler;
10+
private final MixedModeIRMethod method;
11+
12+
MethodFullBuildTask(JITCompiler jitCompiler, MixedModeIRMethod method) {
13+
this.jitCompiler = jitCompiler;
14+
this.method = method;
15+
}
16+
17+
public void run() {
18+
try {
19+
method.completeBuild(new OptInterpretedIRMethod(method.getIRScope(), method.getVisibility(), method.getImplementationClass()));
20+
21+
if (jitCompiler.config.isJitLogging()) {
22+
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), method.getName(), "done building");
23+
}
24+
} catch (Throwable t) {
25+
if (jitCompiler.config.isJitLogging()) {
26+
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), method.getName(),
27+
"Could not build; passes run: " + method.getIRScope().getExecutedPasses(), t.getMessage());
28+
if (jitCompiler.config.isJitLoggingVerbose()) {
29+
t.printStackTrace();
30+
}
31+
}
32+
}
33+
}
34+
}

Diff for: ‎core/src/main/java/org/jruby/internal/runtime/AbstractIRMethod.java

-14
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ public abstract class AbstractIRMethod extends DynamicMethod implements IRMethod
2828
protected final Signature signature;
2929
protected final IRScope method;
3030
protected final StaticScope staticScope;
31-
protected InterpreterContext interpreterContext = null;
32-
protected int callCount = 0;
3331
private MethodData methodData;
3432

3533
public AbstractIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
@@ -38,24 +36,12 @@ public AbstractIRMethod(IRScope method, Visibility visibility, RubyModule implem
3836
this.staticScope = method.getStaticScope();
3937
this.staticScope.determineModule();
4038
this.signature = staticScope.getSignature();
41-
42-
// -1 jit.threshold is way of having interpreter not promote full builds.
43-
if (Options.JIT_THRESHOLD.load() == -1) callCount = -1;
44-
45-
// If we are printing, do the build right at creation time so we can see it
46-
if (IRRuntimeHelpers.shouldPrintIR(implementationClass.getRuntime())) {
47-
ensureInstrsReady();
48-
}
4939
}
5040

5141
public IRScope getIRScope() {
5242
return method;
5343
}
5444

55-
public void setCallCount(int callCount) {
56-
this.callCount = callCount;
57-
}
58-
5945
public StaticScope getStaticScope() {
6046
return staticScope;
6147
}

Diff for: ‎core/src/main/java/org/jruby/internal/runtime/methods/InterpretedIRBodyMethod.java

+42-49
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import org.jruby.RubyModule;
44
import org.jruby.ir.IRScope;
55
import org.jruby.ir.interpreter.InterpreterContext;
6-
import org.jruby.ir.runtime.IRRuntimeHelpers;
76
import org.jruby.runtime.ArgumentDescriptor;
87
import org.jruby.runtime.Block;
98
import org.jruby.runtime.ThreadContext;
@@ -16,8 +15,6 @@
1615
public class InterpretedIRBodyMethod extends InterpretedIRMethod {
1716
public InterpretedIRBodyMethod(IRScope method, RubyModule implementationClass) {
1817
super(method, Visibility.PUBLIC, implementationClass);
19-
20-
callCount = -1;
2118
}
2219

2320
@Override
@@ -27,22 +24,58 @@ public ArgumentDescriptor[] getArgumentDescriptors() {
2724

2825
@Override
2926
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
30-
return call(context, self, clazz, name, block);
27+
return callInternal(context, self, clazz, name, block);
3128
}
3229

3330
@Override
3431
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
35-
if (IRRuntimeHelpers.isDebug()) doDebug();
32+
return callInternal(context, self, clazz, name, block);
33+
}
34+
35+
@Override
36+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
37+
return callInternal(context, self, clazz, name, block);
38+
}
3639

40+
@Override
41+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
3742
return callInternal(context, self, clazz, name, block);
3843
}
3944

45+
@Override
46+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
47+
return callInternal(context, self, clazz, name, block);
48+
}
49+
50+
@Override
51+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
52+
return callInternal(context, self, clazz, name, Block.NULL_BLOCK);
53+
}
54+
55+
@Override
56+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
57+
return callInternal(context, self, clazz, name, Block.NULL_BLOCK);
58+
}
59+
60+
@Override
61+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0) {
62+
return callInternal(context, self, clazz, name, Block.NULL_BLOCK);
63+
}
64+
65+
@Override
66+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1) {
67+
return callInternal(context, self, clazz, name, Block.NULL_BLOCK);
68+
}
69+
70+
@Override
71+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
72+
return callInternal(context, self, clazz, name, Block.NULL_BLOCK);
73+
}
74+
4075
protected IRubyObject callInternal(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
4176
InterpreterContext ic = ensureInstrsReady();
4277

43-
boolean hasExplicitCallProtocol = ic.hasExplicitCallProtocol();
44-
45-
if (!hasExplicitCallProtocol) this.pre(ic, context, self, name, block, getImplementationClass());
78+
this.pre(ic, context, self, name, block, getImplementationClass());
4679

4780
try {
4881
switch (method.getScopeType()) {
@@ -52,7 +85,7 @@ protected IRubyObject callInternal(ThreadContext context, IRubyObject self, Ruby
5285
default: throw new RuntimeException("invalid body method type: " + method);
5386
}
5487
} finally {
55-
if (!hasExplicitCallProtocol) this.post(ic, context);
88+
this.post(ic, context);
5689
}
5790
}
5891

@@ -76,44 +109,4 @@ private IRubyObject interpretWithBacktrace(InterpreterContext ic, ThreadContext
76109
ThreadContext.popBacktrace(context);
77110
}
78111
}
79-
80-
@Override
81-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
82-
return call(context, self, clazz, name, block);
83-
}
84-
85-
@Override
86-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
87-
return call(context, self, clazz, name, block);
88-
}
89-
90-
@Override
91-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
92-
return call(context, self, clazz, name, block);
93-
}
94-
95-
@Override
96-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
97-
return call(context, self, clazz, name, Block.NULL_BLOCK);
98-
}
99-
100-
@Override
101-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
102-
return call(context, self, clazz, name, Block.NULL_BLOCK);
103-
}
104-
105-
@Override
106-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0) {
107-
return call(context, self, clazz, name, Block.NULL_BLOCK);
108-
}
109-
110-
@Override
111-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1) {
112-
return call(context, self, clazz, name, Block.NULL_BLOCK);
113-
}
114-
115-
@Override
116-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
117-
return call(context, self, clazz, name, Block.NULL_BLOCK);
118-
}
119112
}

Diff for: ‎core/src/main/java/org/jruby/internal/runtime/methods/InterpretedIRMetaClassBody.java

-7
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,4 @@ protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject sel
3535
}
3636
context.setCurrentVisibility(getVisibility());
3737
}
38-
39-
@Override
40-
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
41-
if (IRRuntimeHelpers.isDebug()) doDebug();
42-
43-
return callInternal(context, self, clazz, name, block);
44-
}
4538
}

Diff for: ‎core/src/main/java/org/jruby/internal/runtime/methods/InterpretedIRMethod.java

+24-142
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,20 @@
2323
/**
2424
* Method for -X-C (interpreted only execution). See MixedModeIRMethod for inter/JIT method impl.
2525
*/
26-
public class InterpretedIRMethod extends AbstractIRMethod implements Compilable<InterpreterContext> {
26+
public class InterpretedIRMethod extends AbstractIRMethod {
2727
private static final Logger LOG = LoggerFactory.getLogger(InterpretedIRMethod.class);
2828

29-
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG
30-
31-
protected InterpreterContext interpreterContext = null;
32-
protected int callCount = 0;
29+
protected InterpreterContext interpreterContext;
3330

3431
public InterpretedIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
3532
super(method, visibility, implementationClass);
3633

37-
// -1 jit.threshold is way of having interpreter not promote full builds.
38-
if (Options.JIT_THRESHOLD.load() == -1) callCount = -1;
39-
4034
// If we are printing, do the build right at creation time so we can see it
4135
if (IRRuntimeHelpers.shouldPrintIR(implementationClass.getRuntime())) {
42-
ensureInstrsReady();
36+
interpreterContext = ensureInstrsReady();
4337
}
4438
}
4539

46-
public void setCallCount(int callCount) {
47-
this.callCount = callCount;
48-
}
49-
5040
protected void post(InterpreterContext ic, ThreadContext context) {
5141
// update call stacks (pop: ..)
5242
context.popFrame();
@@ -73,6 +63,11 @@ public InterpreterContext ensureInstrsReady() {
7363
}
7464
interpreterContext = method.getInterpreterContext();
7565

66+
if (IRRuntimeHelpers.isDebug()) {
67+
LOG.info("Executing '" + method.getName() + "'");
68+
LOG.info(method.debugOutput());
69+
}
70+
7671
if (IRRuntimeHelpers.shouldPrintIR(implementationClass.getRuntime())) {
7772
ByteArrayOutputStream baos = IRDumper.printIR(method, false, true);
7873

@@ -85,224 +80,111 @@ public InterpreterContext ensureInstrsReady() {
8580

8681
@Override
8782
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
88-
if (IRRuntimeHelpers.isDebug()) doDebug();
89-
90-
if (callCount >= 0) promoteToFullBuild(context);
9183
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, args, block);
9284
}
9385

9486
@Override
9587
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
96-
if (IRRuntimeHelpers.isDebug()) doDebug();
97-
98-
if (callCount >= 0) promoteToFullBuild(context);
9988
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, args, Block.NULL_BLOCK);
10089
}
10190

10291
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
10392
IRubyObject self, String name, IRubyObject[] args, Block block) {
10493
try {
10594
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
106-
107-
if (ic.hasExplicitCallProtocol()) {
108-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
109-
} else {
110-
try {
111-
pre(ic, context, self, name, block, implClass);
112-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
113-
} finally {
114-
post(ic, context);
115-
}
116-
}
95+
pre(ic, context, self, name, block, implClass);
96+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
11797
} finally {
98+
post(ic, context);
11899
ThreadContext.popBacktrace(context);
119100
}
120101
}
121102

122103
@Override
123104
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
124-
if (IRRuntimeHelpers.isDebug()) doDebug();
125-
126-
if (callCount >= 0) promoteToFullBuild(context);
127-
128105
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, block);
129106
}
130107

131108
@Override
132109
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
133-
if (IRRuntimeHelpers.isDebug()) doDebug();
134-
135-
if (callCount >= 0) promoteToFullBuild(context);
136-
137110
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, Block.NULL_BLOCK);
138111
}
139112

140113
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
141114
IRubyObject self, String name, Block block) {
142115
try {
143116
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
144-
145-
if (ic.hasExplicitCallProtocol()) {
146-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
147-
} else {
148-
try {
149-
pre(ic, context, self, name, block, implClass);
150-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
151-
} finally {
152-
post(ic, context);
153-
}
154-
}
117+
pre(ic, context, self, name, block, implClass);
118+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
155119
} finally {
120+
post(ic, context);
156121
ThreadContext.popBacktrace(context);
157122
}
158123
}
159124

160125
@Override
161126
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
162-
if (IRRuntimeHelpers.isDebug()) doDebug();
163-
164-
if (callCount >= 0) promoteToFullBuild(context);
165127
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, block);
166128
}
167129

168130
@Override
169131
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0) {
170-
if (IRRuntimeHelpers.isDebug()) doDebug();
171-
172-
if (callCount >= 0) promoteToFullBuild(context);
173132
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, Block.NULL_BLOCK);
174133
}
175134

176135
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
177136
IRubyObject self, String name, IRubyObject arg1, Block block) {
178137
try {
179138
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
180-
181-
if (ic.hasExplicitCallProtocol()) {
182-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
183-
} else {
184-
try {
185-
pre(ic, context, self, name, block, implClass);
186-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
187-
} finally {
188-
post(ic, context);
189-
}
190-
}
139+
pre(ic, context, self, name, block, implClass);
140+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
191141
} finally {
142+
post(ic, context);
192143
ThreadContext.popBacktrace(context);
193144
}
194145
}
195146

196147
@Override
197148
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
198-
if (IRRuntimeHelpers.isDebug()) doDebug();
199-
200-
if (callCount >= 0) promoteToFullBuild(context);
201149
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, block);
202150
}
203151

204152
@Override
205153
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1) {
206-
if (IRRuntimeHelpers.isDebug()) doDebug();
207-
208-
if (callCount >= 0) promoteToFullBuild(context);
209154
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, Block.NULL_BLOCK);
210155
}
211156

212157
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
213-
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, Block block) {
158+
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, Block block) {
214159
try {
215160
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
216-
217-
if (ic.hasExplicitCallProtocol()) {
218-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
219-
} else {
220-
try {
221-
pre(ic, context, self, name, block, implClass);
222-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
223-
} finally {
224-
post(ic, context);
225-
}
226-
}
161+
pre(ic, context, self, name, block, implClass);
162+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
227163
} finally {
164+
post(ic, context);
228165
ThreadContext.popBacktrace(context);
229166
}
230167
}
231168

232169
@Override
233170
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
234-
if (IRRuntimeHelpers.isDebug()) doDebug();
235-
236-
if (callCount >= 0) promoteToFullBuild(context);
237171
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, arg2, block);
238172
}
239173

240174
@Override
241175
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
242-
if (IRRuntimeHelpers.isDebug()) doDebug();
243-
244-
if (callCount >= 0) promoteToFullBuild(context);
245176
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, arg2, Block.NULL_BLOCK);
246177
}
247178

248179
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
249180
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
250181
try {
251182
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
252-
253-
if (ic.hasExplicitCallProtocol()) {
254-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
255-
} else {
256-
try {
257-
pre(ic, context, self, name, block, implClass);
258-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
259-
} finally {
260-
post(ic, context);
261-
}
262-
}
183+
pre(ic, context, self, name, block, implClass);
184+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
263185
} finally {
186+
post(ic, context);
264187
ThreadContext.popBacktrace(context);
265188
}
266-
267-
}
268-
269-
protected void doDebug() {
270-
// FIXME: This is printing out IRScope CFG but JIT may be active and it might not reflect
271-
// currently executing. Move into JIT and into interp since they will be getting CFG from
272-
// different sources
273-
// FIXME: This is only printing out CFG once. If we keep applying more passes then we
274-
// will want to print out after those new passes.
275-
ensureInstrsReady();
276-
LOG.info("Executing '" + method.getName() + "'");
277-
if (!displayedCFG) {
278-
LOG.info(method.debugOutput());
279-
displayedCFG = true;
280-
}
281-
}
282-
283-
public void completeBuild(InterpreterContext interpreterContext) {
284-
this.interpreterContext = interpreterContext;
285-
// Reset so that we can see the new instr dump again
286-
this.displayedCFG = false;
287-
}
288-
289-
// Unlike JIT in MixedMode this will always successfully build but if using executor pool it may take a while
290-
// and replace interpreterContext asynchronously.
291-
private void promoteToFullBuild(ThreadContext context) {
292-
Ruby runtime = context.runtime;
293-
294-
if (runtime.isBooting() && !Options.JIT_KERNEL.load()) return; // don't Promote to full build during runtime boot
295-
296-
if (callCount++ >= Options.JIT_THRESHOLD.load()) runtime.getJITCompiler().buildThresholdReached(context, this);
297-
298-
if (IRRuntimeHelpers.shouldPrintIR(implementationClass.getRuntime())) {
299-
ByteArrayOutputStream baos = IRDumper.printIR(method, true, true);
300-
301-
LOG.info("Printing full IR for " + method.getName() + ":\n" + new String(baos.toByteArray()));
302-
}
303-
}
304-
305-
public String getClassName(ThreadContext context) {
306-
return null;
307189
}
308190
}

Diff for: ‎core/src/main/java/org/jruby/internal/runtime/methods/MixedModeIRMethod.java

+16-185
Original file line numberDiff line numberDiff line change
@@ -26,241 +26,72 @@ public class MixedModeIRMethod extends AbstractIRMethod implements Compilable<Dy
2626
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG
2727

2828
private volatile int callCount = 0;
29-
private volatile DynamicMethod actualMethod;
29+
private volatile InterpretedIRMethod baseMethod;
30+
private volatile DynamicMethod jittedMethod;
3031

3132
public MixedModeIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
3233
super(method, visibility, implementationClass);
34+
35+
this.baseMethod = new InterpretedIRMethod(method, visibility, implementationClass);
36+
3337
getStaticScope().determineModule();
3438

35-
// disable JIT if JIT is disabled
36-
if (!implementationClass.getRuntime().getInstanceConfig().getCompileMode().shouldJIT() ||
37-
Options.JIT_THRESHOLD.load() < 0) {
39+
// disable JIT if threshold is below zero
40+
if (Options.JIT_THRESHOLD.load() < 0) {
3841
callCount = -1;
3942
}
4043
}
4144

4245
public DynamicMethod getActualMethod() {
43-
return actualMethod;
44-
}
45-
46-
protected void post(InterpreterContext ic, ThreadContext context) {
47-
// update call stacks (pop: ..)
48-
context.popFrame();
49-
if (ic.popDynScope()) {
50-
context.popScope();
51-
}
52-
}
53-
54-
protected void pre(InterpreterContext ic, ThreadContext context, IRubyObject self, String name, Block block, RubyModule implClass) {
55-
// update call stacks (push: frame, class, scope, etc.)
56-
context.preMethodFrameOnly(implClass, name, self, block);
57-
if (ic.pushNewDynScope()) {
58-
context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope()));
59-
}
46+
return jittedMethod != null ? jittedMethod : baseMethod;
6047
}
6148

6249
// FIXME: for subclasses we should override this method since it can be simple get
6350
// FIXME: to avoid cost of synch call in lazilyacquire we can save the ic here
6451
public InterpreterContext ensureInstrsReady() {
65-
if (method instanceof IRMethod) {
66-
return ((IRMethod) method).lazilyAcquireInterpreterContext();
67-
}
68-
69-
InterpreterContext ic = method.getInterpreterContext();
70-
71-
if (IRRuntimeHelpers.shouldPrintIR(implementationClass.getRuntime())) {
72-
ByteArrayOutputStream baos = IRDumper.printIR(method, false);
73-
74-
LOG.info("Printing simple IR for " + method.getName() + ":\n" + new String(baos.toByteArray()));
75-
}
76-
77-
return ic;
52+
return baseMethod.ensureInstrsReady();
7853
}
7954

8055
@Override
8156
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
82-
if (IRRuntimeHelpers.isDebug()) doDebug();
83-
8457
if (callCount >= 0) tryJit(context);
8558

86-
DynamicMethod jittedMethod = actualMethod;
87-
if (jittedMethod != null) {
88-
return jittedMethod.call(context, self, clazz, name, args, block);
89-
}
90-
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, args, block);
91-
}
92-
93-
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
94-
IRubyObject self, String name, IRubyObject[] args, Block block) {
95-
try {
96-
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
97-
98-
if (ic.hasExplicitCallProtocol()) {
99-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
100-
} else {
101-
try {
102-
this.pre(ic, context, self, name, block, implClass);
103-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
104-
} finally {
105-
this.post(ic, context);
106-
}
107-
}
108-
} finally {
109-
ThreadContext.popBacktrace(context);
110-
}
59+
return getActualMethod().call(context, self, clazz, name, args, block);
11160
}
11261

11362
@Override
11463
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
115-
if (IRRuntimeHelpers.isDebug()) doDebug();
116-
11764
if (callCount >= 0) tryJit(context);
11865

119-
DynamicMethod jittedMethod = actualMethod;
120-
if (jittedMethod != null) {
121-
return jittedMethod.call(context, self, clazz, name, block);
122-
}
123-
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, block);
124-
}
125-
126-
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
127-
IRubyObject self, String name, Block block) {
128-
try {
129-
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
130-
131-
if (ic.hasExplicitCallProtocol()) {
132-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
133-
} else {
134-
try {
135-
this.pre(ic, context, self, name, block, implClass);
136-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
137-
} finally {
138-
this.post(ic, context);
139-
}
140-
}
141-
} finally {
142-
ThreadContext.popBacktrace(context);
143-
}
66+
return getActualMethod().call(context, self, clazz, name, block);
14467
}
14568

14669
@Override
14770
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
148-
if (IRRuntimeHelpers.isDebug()) doDebug();
149-
15071
if (callCount >= 0) tryJit(context);
15172

152-
DynamicMethod jittedMethod = actualMethod;
153-
if (jittedMethod != null) {
154-
return jittedMethod.call(context, self, clazz, name, arg0, block);
155-
}
156-
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, arg0, block);
157-
}
158-
159-
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
160-
IRubyObject self, String name, IRubyObject arg1, Block block) {
161-
try {
162-
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
163-
164-
if (ic.hasExplicitCallProtocol()) {
165-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
166-
} else {
167-
try {
168-
this.pre(ic, context, self, name, block, implClass);
169-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
170-
} finally {
171-
this.post(ic, context);
172-
}
173-
}
174-
} finally {
175-
ThreadContext.popBacktrace(context);
176-
}
73+
return getActualMethod().call(context, self, clazz, name, arg0, block);
17774
}
17875

17976
@Override
18077
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
181-
if (IRRuntimeHelpers.isDebug()) doDebug();
182-
18378
if (callCount >= 0) tryJit(context);
18479

185-
DynamicMethod jittedMethod = actualMethod;
186-
if (jittedMethod != null) {
187-
return jittedMethod.call(context, self, clazz, name, arg0, arg1, block);
188-
}
189-
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, arg0, arg1, block);
190-
}
191-
192-
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
193-
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, Block block) {
194-
try {
195-
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
196-
197-
if (ic.hasExplicitCallProtocol()) {
198-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
199-
} else {
200-
try {
201-
this.pre(ic, context, self, name, block, implClass);
202-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
203-
} finally {
204-
this.post(ic, context);
205-
}
206-
}
207-
} finally {
208-
ThreadContext.popBacktrace(context);
209-
}
80+
return getActualMethod().call(context, self, clazz, name, arg0, arg1, block);
21081
}
21182

21283
@Override
21384
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
214-
if (IRRuntimeHelpers.isDebug()) doDebug();
21585
if (callCount >= 0) tryJit(context);
21686

217-
DynamicMethod jittedMethod = actualMethod;
218-
if (jittedMethod != null) {
219-
return jittedMethod.call(context, self, clazz, name, arg0, arg1, arg2, block);
220-
}
221-
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, arg0, arg1, arg2, block);
222-
}
223-
224-
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
225-
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
226-
try {
227-
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
228-
229-
if (ic.hasExplicitCallProtocol()) {
230-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
231-
} else {
232-
try {
233-
this.pre(ic, context, self, name, block, implClass);
234-
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
235-
} finally {
236-
this.post(ic, context);
237-
}
238-
}
239-
} finally {
240-
ThreadContext.popBacktrace(context);
241-
}
242-
243-
}
244-
245-
private void doDebug() {
246-
// FIXME: This is printing out IRScope CFG but JIT may be active and it might not reflect
247-
// currently executing. Move into JIT and into interp since they will be getting CFG from
248-
// different sources
249-
// FIXME: This is only printing out CFG once. If we keep applying more passes then we
250-
// will want to print out after those new passes.
251-
ensureInstrsReady();
252-
LOG.info("Executing '" + method.getName() + "'");
253-
if (!displayedCFG) {
254-
LOG.info(method.debugOutput());
255-
displayedCFG = true;
256-
}
87+
return getActualMethod().call(context, self, clazz, name, arg0, arg1, arg2, block);
25788
}
25889

25990
@Override
26091
public void completeBuild(DynamicMethod newMethod) {
26192
setCallCount(-1);
26293
newMethod.serialNumber = this.serialNumber;
263-
actualMethod = newMethod;
94+
jittedMethod = newMethod;
26495
getImplementationClass().invalidateCacheDescendants();
26596
}
26697

@@ -298,7 +129,7 @@ public String getClassName(ThreadContext context) {
298129
public DynamicMethod dup() {
299130
MixedModeIRMethod x = (MixedModeIRMethod) super.dup();
300131
x.callCount = callCount;
301-
x.actualMethod = actualMethod;
132+
x.baseMethod = baseMethod;
302133

303134
return x;
304135
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package org.jruby.internal.runtime.methods;
2+
3+
import org.jruby.RubyModule;
4+
import org.jruby.internal.runtime.AbstractIRMethod;
5+
import org.jruby.ir.IRMethod;
6+
import org.jruby.ir.IRScope;
7+
import org.jruby.ir.interpreter.FullInterpreterContext;
8+
import org.jruby.ir.interpreter.InterpreterContext;
9+
import org.jruby.ir.persistence.IRDumper;
10+
import org.jruby.ir.runtime.IRRuntimeHelpers;
11+
import org.jruby.runtime.Block;
12+
import org.jruby.runtime.DynamicScope;
13+
import org.jruby.runtime.ThreadContext;
14+
import org.jruby.runtime.Visibility;
15+
import org.jruby.runtime.builtin.IRubyObject;
16+
import org.jruby.util.log.Logger;
17+
import org.jruby.util.log.LoggerFactory;
18+
19+
import java.io.ByteArrayOutputStream;
20+
21+
/**
22+
* Method for -X-C (interpreted only execution). See MixedModeIRMethod for inter/JIT method impl.
23+
*/
24+
public class OptInterpretedIRMethod extends AbstractIRMethod {
25+
private static final Logger LOG = LoggerFactory.getLogger(OptInterpretedIRMethod.class);
26+
27+
protected FullInterpreterContext interpreterContext;
28+
29+
public OptInterpretedIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) {
30+
super(method, visibility, implementationClass);
31+
32+
interpreterContext = method.prepareFullBuild();
33+
}
34+
35+
@Override
36+
public InterpreterContext ensureInstrsReady() {
37+
return interpreterContext;
38+
}
39+
40+
@Override
41+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
42+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, args, block);
43+
}
44+
45+
@Override
46+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
47+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, args, Block.NULL_BLOCK);
48+
}
49+
50+
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
51+
IRubyObject self, String name, IRubyObject[] args, Block block) {
52+
try {
53+
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
54+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, args, block);
55+
} finally {
56+
ThreadContext.popBacktrace(context);
57+
}
58+
}
59+
60+
@Override
61+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
62+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, block);
63+
}
64+
65+
@Override
66+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
67+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, Block.NULL_BLOCK);
68+
}
69+
70+
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
71+
IRubyObject self, String name, Block block) {
72+
try {
73+
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
74+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, block);
75+
} finally {
76+
ThreadContext.popBacktrace(context);
77+
}
78+
}
79+
80+
@Override
81+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
82+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, block);
83+
}
84+
85+
@Override
86+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0) {
87+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, Block.NULL_BLOCK);
88+
}
89+
90+
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
91+
IRubyObject self, String name, IRubyObject arg1, Block block) {
92+
try {
93+
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
94+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, block);
95+
} finally {
96+
ThreadContext.popBacktrace(context);
97+
}
98+
}
99+
100+
@Override
101+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
102+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, block);
103+
}
104+
105+
@Override
106+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1) {
107+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, Block.NULL_BLOCK);
108+
}
109+
110+
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
111+
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, Block block) {
112+
try {
113+
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
114+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, block);
115+
} finally {
116+
ThreadContext.popBacktrace(context);
117+
}
118+
}
119+
120+
@Override
121+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
122+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, arg2, block);
123+
}
124+
125+
@Override
126+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
127+
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass(), self, name, arg0, arg1, arg2, Block.NULL_BLOCK);
128+
}
129+
130+
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass,
131+
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) {
132+
try {
133+
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
134+
return ic.getEngine().interpret(context, null, self, ic, implClass, name, arg1, arg2, arg3, block);
135+
} finally {
136+
ThreadContext.popBacktrace(context);
137+
}
138+
}
139+
}

Diff for: ‎core/src/main/java/org/jruby/ir/IRClosure.java

+5-13
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;
1515
import org.jruby.parser.StaticScope;
1616
import org.jruby.runtime.ArgumentDescriptor;
17-
import org.jruby.runtime.BlockBody;
1817
import org.jruby.runtime.Helpers;
19-
import org.jruby.runtime.IRBlockBody;
20-
import org.jruby.runtime.MixedModeIRBlockBody;
18+
import org.jruby.runtime.AbstractIRBlockBody;
2119
import org.jruby.runtime.InterpretedIRBlockBody;
2220
import org.jruby.runtime.Signature;
2321
import org.objectweb.asm.Handle;
@@ -43,7 +41,7 @@ public class IRClosure extends IRScope {
4341
protected ArgumentDescriptor[] argDesc = ArgumentDescriptor.EMPTY_ARRAY;
4442

4543
/** Added for interp/JIT purposes */
46-
private IRBlockBody body;
44+
private AbstractIRBlockBody body;
4745

4846
/** Added for JIT purposes */
4947
private Handle handle;
@@ -70,8 +68,7 @@ protected IRClosure(IRClosure c, IRScope lexicalParent, int closureId, String fu
7068
if (getManager().isDryRun()) {
7169
this.body = null;
7270
} else {
73-
boolean shouldJit = getManager().getInstanceConfig().getCompileMode().shouldJIT();
74-
this.body = shouldJit ? new MixedModeIRBlockBody(c, c.getSignature()) : new InterpretedIRBlockBody(c, c.getSignature());
71+
this.body = new InterpretedIRBlockBody(c, c.getSignature());
7572
}
7673

7774
this.signature = c.signature;
@@ -105,8 +102,7 @@ public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, Stati
105102
if (getManager().isDryRun()) {
106103
this.body = null;
107104
} else {
108-
boolean shouldJit = manager.getInstanceConfig().getCompileMode().shouldJIT();
109-
this.body = shouldJit ? new MixedModeIRBlockBody(this, signature) : new InterpretedIRBlockBody(this, signature);
105+
this.body = new InterpretedIRBlockBody(this, signature);
110106
if (staticScope != null && !isBeginEndBlock) {
111107
staticScope.setIRScope(this);
112108
staticScope.setScopeType(this.getScopeType());
@@ -188,11 +184,7 @@ public boolean isFlipScope() {
188184
return false;
189185
}
190186

191-
public String toStringBody() {
192-
return new StringBuilder(getName()).append(" = {\n").append(toStringInstrs()).append("\n}\n\n").toString();
193-
}
194-
195-
public BlockBody getBlockBody() {
187+
public AbstractIRBlockBody getBlockBody() {
196188
return body;
197189
}
198190

Diff for: ‎core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -1403,12 +1403,8 @@ public static RubyModule newRubyClassFromIR(Ruby runtime, IRScope irClassBody, O
14031403
public static void defInterpretedClassMethod(ThreadContext context, IRScope method, IRubyObject obj) {
14041404
RubyClass rubyClass = checkClassForDef(context, method, obj);
14051405

1406-
DynamicMethod newMethod;
1407-
if (context.runtime.getInstanceConfig().getCompileMode() == RubyInstanceConfig.CompileMode.OFF) {
1408-
newMethod = new InterpretedIRMethod(method, Visibility.PUBLIC, rubyClass);
1409-
} else {
1410-
newMethod = new MixedModeIRMethod(method, Visibility.PUBLIC, rubyClass);
1411-
}
1406+
DynamicMethod newMethod = new MixedModeIRMethod(method, Visibility.PUBLIC, rubyClass);
1407+
14121408
// FIXME: needs checkID and proper encoding to force hard symbol
14131409
rubyClass.addMethod(method.getName(), newMethod);
14141410
if (!rubyClass.isRefinement()) {
@@ -1458,12 +1454,7 @@ public static void defInterpretedInstanceMethod(ThreadContext context, IRScope m
14581454
Visibility currVisibility = context.getCurrentVisibility();
14591455
Visibility newVisibility = Helpers.performNormalMethodChecksAndDetermineVisibility(runtime, rubyClass, method.getName(), currVisibility);
14601456

1461-
DynamicMethod newMethod;
1462-
if (context.runtime.getInstanceConfig().getCompileMode() == RubyInstanceConfig.CompileMode.OFF) {
1463-
newMethod = new InterpretedIRMethod(method, newVisibility, rubyClass);
1464-
} else {
1465-
newMethod = new MixedModeIRMethod(method, newVisibility, rubyClass);
1466-
}
1457+
DynamicMethod newMethod = new MixedModeIRMethod(method, newVisibility, rubyClass);
14671458

14681459
// FIXME: needs checkID and proper encoding to force hard symbol
14691460
Helpers.addInstanceMethod(rubyClass, method.getName(), newMethod, currVisibility, context, runtime);

Diff for: ‎core/src/main/java/org/jruby/runtime/IRBlockBody.java renamed to ‎core/src/main/java/org/jruby/runtime/AbstractIRBlockBody.java

+61-47
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,34 @@
1212
import static org.jruby.RubyArray.newArray;
1313
import static org.jruby.runtime.Helpers.arrayOf;
1414

15-
public abstract class IRBlockBody extends ContextAwareBlockBody {
15+
public abstract class AbstractIRBlockBody extends ContextAwareBlockBody {
1616
protected final String fileName;
1717
protected final int lineNumber;
1818
protected final IRClosure closure;
1919
ThreadLocal<EvalType> evalType;
2020

21-
public IRBlockBody(IRScope closure, Signature signature) {
21+
public AbstractIRBlockBody(IRScope closure, Signature signature) {
2222
// ThreadLocal not set by default to avoid having many thread-local values initialized
2323
// servers such as Tomcat tend to do thread-local checks when un-deploying apps,
2424
// for JRuby leads to 100s of SEVERE warnings for a mid-size (booted) Rails app
2525
this(closure, signature, new ThreadLocal());
2626
}
2727

28-
/* internal */ IRBlockBody(IRScope closure, Signature signature, ThreadLocal evalType) {
28+
/* internal */ AbstractIRBlockBody(IRScope closure, Signature signature, ThreadLocal evalType) {
2929
super(closure.getStaticScope(), signature);
3030
this.closure = (IRClosure) closure;
3131
this.fileName = closure.getFileName();
3232
this.lineNumber = closure.getLineNumber();
3333
this.evalType = evalType;
3434
}
3535

36+
@Override
3637
public final EvalType getEvalType() {
3738
final EvalType type = this.evalType.get();
3839
return type == null ? EvalType.NONE : type;
3940
}
4041

42+
@Override
4143
public void setEvalType(final EvalType type) {
4244
if (type == null || type == EvalType.NONE) {
4345
this.evalType.remove();
@@ -46,6 +48,7 @@ public void setEvalType(final EvalType type) {
4648
}
4749
}
4850

51+
@Override
4952
public IRubyObject yield(ThreadContext context, Block block, IRubyObject value, IRubyObject self, Block blockArg) {
5053
if (canInvokeDirect()) {
5154
return invokeYieldDirect(context, block, arrayOf(value), blockArg, self);
@@ -54,6 +57,7 @@ public IRubyObject yield(ThreadContext context, Block block, IRubyObject value,
5457
}
5558
}
5659

60+
@Override
5761
public IRubyObject yield(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
5862
if (canInvokeDirect()) {
5963
return invokeYieldDirect(context, block, args, blockArg, self);
@@ -87,52 +91,46 @@ public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args,
8791

8892
@Override
8993
public IRubyObject yieldSpecific(ThreadContext context, Block block) {
90-
return invokeSpecific(context, block, Block.NULL_BLOCK, null);
94+
return invokeYieldSpecific(context, block, Block.NULL_BLOCK, null);
9195
}
9296

9397
@Override
9498
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
95-
return invokeSpecific(context, block, arg0, Block.NULL_BLOCK, null);
99+
return invokeYieldSpecific(context, block, arg0, Block.NULL_BLOCK, null);
96100
}
97101

98102
@Override
99103
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
100-
return invokeSpecific(context, block, arg0, arg1, Block.NULL_BLOCK, null);
104+
return invokeYieldSpecific(context, block, arg0, arg1, Block.NULL_BLOCK, null);
101105
}
102106

103107
@Override
104108
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
105-
return invokeSpecific(context, block, arg0, arg1, arg2, Block.NULL_BLOCK, null);
109+
return invokeYieldSpecific(context, block, arg0, arg1, arg2, Block.NULL_BLOCK, null);
106110
}
107111

108-
protected abstract boolean canInvokeDirect();
112+
protected boolean canInvokeDirect() {
113+
return false;
114+
}
109115

110-
/**
111-
* This is the only method that *must* be implemented in blocks, and represents the bulk of logic.
112-
*
113-
* Other forms empty into this one and can be overridden to optimize specific paths.
114-
*
115-
* @param context
116-
* @param block
117-
* @param args
118-
* @param blockArg
119-
* @param self
120-
* @return
121-
*/
122-
protected abstract IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self);
116+
protected IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
117+
throw new UnsupportedOperationException("invoke not implemented");
118+
}
123119

124-
protected abstract IRubyObject invokeCallDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self);
120+
protected IRubyObject invokeCallDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
121+
throw new UnsupportedOperationException("invokeCallDirect not implemented");
122+
}
125123

126-
protected abstract IRubyObject invokeYieldDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self);
124+
protected IRubyObject invokeYieldDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
125+
throw new UnsupportedOperationException("invokeYieldDirect not implemented");
126+
}
127127

128128
IRubyObject invokeYield(ThreadContext context, Block block, IRubyObject value, Block blockArg, IRubyObject self) {
129129
if (block.isLambda()) return invokeLambda(context, block, value, blockArg, self);
130130

131131
int blockArity = signature.arityValue();
132132

133-
if (value == null) { // no args case from BlockBody.yieldSpecific
134-
return invoke(context, block, IRubyObject.NULL_ARRAY, blockArg, self);
135-
} else if (!signature.hasKwargs() && blockArity >= -1 && blockArity <= 1) {
133+
if (!signature.hasKwargs() && blockArity >= -1 && blockArity <= 1) {
136134
return invoke(context, block, arrayOf(value), blockArg, self);
137135
} else {
138136
return invoke(context, block, toAry(context, value), blockArg, self);
@@ -141,9 +139,7 @@ IRubyObject invokeYield(ThreadContext context, Block block, IRubyObject value, B
141139

142140
IRubyObject invokeLambda(ThreadContext context, Block block, IRubyObject value, Block blockArg, IRubyObject self) {
143141
// Lambda does not splat arrays even if a rest arg is present when it wants a single parameter filled.
144-
if (value == null) { // no args case from BlockBody.yieldSpecific
145-
return invokeLambda(context, block, IRubyObject.NULL_ARRAY, blockArg, self);
146-
} else if (signature.required() == 1 || signature.arityValue() == -1) {
142+
if (signature.required() == 1 || signature.arityValue() == -1) {
147143
return invokeLambda(context, block, arrayOf(value), blockArg, self);
148144
} else {
149145
return invokeLambda(context, block, toAry(context, value), blockArg, self);
@@ -156,7 +152,7 @@ IRubyObject invokeLambda(ThreadContext context, Block block, IRubyObject[] args,
156152
return invoke(context, block, args, blockArg, self);
157153
}
158154

159-
IRubyObject invokeSpecific(ThreadContext context, Block block, Block blockArg, IRubyObject self) {
155+
IRubyObject invokeYieldSpecific(ThreadContext context, Block block, Block blockArg, IRubyObject self) {
160156
if (canInvokeDirect()) {
161157
return invokeYieldDirect(context, block, null, blockArg, self);
162158
} else {
@@ -166,8 +162,8 @@ IRubyObject invokeSpecific(ThreadContext context, Block block, Block blockArg, I
166162
}
167163
}
168164

169-
IRubyObject invokeSpecific(ThreadContext context, Block block, IRubyObject arg0, Block blockArg, IRubyObject self) {
170-
if (canInvokeDirect()) return invokeSpecificDirect(context, block, arg0, blockArg, self);
165+
IRubyObject invokeYieldSpecific(ThreadContext context, Block block, IRubyObject arg0, Block blockArg, IRubyObject self) {
166+
if (canInvokeDirect()) return invokeYieldSpecificDirect(context, block, arg0, blockArg, self);
171167

172168
if (arg0 instanceof RubyArray) {
173169
// Unwrap the array arg
@@ -182,7 +178,7 @@ IRubyObject invokeSpecific(ThreadContext context, Block block, IRubyObject arg0,
182178
return invokeYield(context, block, arg0, blockArg, self);
183179
}
184180

185-
IRubyObject invokeSpecificDirect(ThreadContext context, Block block, IRubyObject arg0, Block blockArg, IRubyObject self) {
181+
IRubyObject invokeYieldSpecificDirect(ThreadContext context, Block block, IRubyObject arg0, Block blockArg, IRubyObject self) {
186182
IRubyObject[] args;
187183
if (arg0 instanceof RubyArray) {
188184
// Unwrap the array arg
@@ -193,37 +189,55 @@ IRubyObject invokeSpecificDirect(ThreadContext context, Block block, IRubyObject
193189
return invokeYieldDirect(context, block, args, blockArg, self);
194190
}
195191

196-
IRubyObject invokeSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg, IRubyObject self) {
197-
if (canInvokeDirect()) return invokeSpecificDirect(context, block, arg0, arg1, blockArg, self);
192+
IRubyObject invokeYieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg, IRubyObject self) {
193+
if (canInvokeDirect()) return invokeYieldSpecificDirect(context, block, arg0, arg1, blockArg, self);
194+
195+
IRubyObject[] args = boxArgs(context, block, arg0, arg1);
196+
197+
return invoke(context, block, args, blockArg, self);
198+
}
199+
200+
private IRubyObject[] boxArgs(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
201+
IRubyObject[] args;
198202

199203
switch (signature.arityValue()) {
200204
case 0:
201-
return invoke(context, block, IRubyObject.NULL_ARRAY, blockArg, self);
205+
args = IRubyObject.NULL_ARRAY;
206+
break;
202207
case 1:
203-
return invoke(context, block, arrayOf(newArray(context.runtime, arg0, arg1)), blockArg, self);
208+
args = arrayOf(newArray(context.runtime, arg0, arg1));
209+
break;
204210
default:
205-
IRubyObject[] args = arrayOf(arg0, arg1);
211+
args = arrayOf(arg0, arg1);
206212
if (block.isLambda()) signature.checkArity(context.runtime, args);
207-
return invoke(context, block, args, blockArg, self);
208213
}
214+
return args;
209215
}
210216

211-
IRubyObject invokeSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg, IRubyObject self) {
212-
if (canInvokeDirect()) return invokeSpecificDirect(context, block, arg0, arg1, arg2, blockArg, self);
217+
private IRubyObject[] boxArgs(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
218+
IRubyObject[] args;
213219

214220
switch (signature.arityValue()) {
215221
case 0:
216-
return invoke(context, block, IRubyObject.NULL_ARRAY, blockArg, self);
222+
args = IRubyObject.NULL_ARRAY;
223+
break;
217224
case 1:
218-
return invoke(context, block, arrayOf(newArray(context.runtime, arg0, arg1, arg2)), blockArg, self);
225+
args = arrayOf(newArray(context.runtime, arg0, arg1, arg2));
226+
break;
219227
default:
220-
IRubyObject[] args = arrayOf(arg0, arg1, arg2);
228+
args = arrayOf(arg0, arg1, arg2);
221229
if (block.isLambda()) signature.checkArity(context.runtime, args);
222-
return invoke(context, block, args, blockArg, self);
223230
}
231+
return args;
232+
}
233+
234+
IRubyObject invokeYieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg, IRubyObject self) {
235+
if (canInvokeDirect()) return invokeYieldSpecificDirect(context, block, arg0, arg1, arg2, blockArg, self);
236+
237+
return invoke(context, block, boxArgs(context, block, arg0, arg1, arg2), blockArg, self);
224238
}
225239

226-
IRubyObject invokeSpecificDirect(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg, IRubyObject self) {
240+
IRubyObject invokeYieldSpecificDirect(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg, IRubyObject self) {
227241
switch (signature.arityValue()) {
228242
case 0:
229243
return invokeYieldDirect(context, block, arrayOf(arg0, arg1), blockArg, self);
@@ -234,7 +248,7 @@ IRubyObject invokeSpecificDirect(ThreadContext context, Block block, IRubyObject
234248
}
235249
}
236250

237-
IRubyObject invokeSpecificDirect(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg, IRubyObject self) {
251+
IRubyObject invokeYieldSpecificDirect(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg, IRubyObject self) {
238252
switch (signature.arityValue()) {
239253
case 0:
240254
return invokeYieldDirect(context, block, arrayOf(arg0, arg1, arg2), blockArg, self);

Diff for: ‎core/src/main/java/org/jruby/runtime/BlockBody.java

+13-13
Original file line numberDiff line numberDiff line change
@@ -77,32 +77,32 @@ public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args,
7777
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null, blockArg);
7878
}
7979

80-
public IRubyObject yieldSpecific(ThreadContext context, Block block) {
81-
return yield(context, block, IRubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
82-
}
8380
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, Block blockArg) {
8481
return yield(context, block, prepareArgumentsForCall(context, arrayOf(arg0), block.type), null, blockArg);
8582
}
8683

87-
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
88-
return yield(context, block, arg0, null, Block.NULL_BLOCK);
84+
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg) {
85+
return yield(context, block, prepareArgumentsForCall(context, arrayOf(arg0, arg1), block.type), null, blockArg);
8986
}
9087

91-
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg) {
92-
return yield(context, block, prepareArgumentsForCall(context, new IRubyObject[] {arg0, arg1}, block.type), null, blockArg);
88+
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg) {
89+
return yield(context, block, prepareArgumentsForCall(context, arrayOf(arg0, arg1, arg2), block.type), null, blockArg);
9390
}
9491

95-
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
96-
return yield(context, block, new IRubyObject[] { arg0, arg1 }, null, Block.NULL_BLOCK);
92+
public IRubyObject yieldSpecific(ThreadContext context, Block block) {
93+
return yield(context, block, IRubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
9794
}
9895

99-
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg) {
100-
IRubyObject[] args = new IRubyObject[] {arg0, arg1, arg2};
101-
return yield(context, block, prepareArgumentsForCall(context, args, block.type), null, blockArg);
96+
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
97+
return yield(context, block, arg0, null, Block.NULL_BLOCK);
98+
}
99+
100+
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
101+
return yield(context, block, arrayOf(arg0, arg1), null, Block.NULL_BLOCK);
102102
}
103103

104104
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
105-
return yield(context, block, new IRubyObject[] { arg0, arg1, arg2 }, null, Block.NULL_BLOCK);
105+
return yield(context, block, arrayOf(arg0, arg1, arg2), null, Block.NULL_BLOCK);
106106
}
107107

108108
public abstract StaticScope getStaticScope();

Diff for: ‎core/src/main/java/org/jruby/runtime/CompiledIRBlockBody.java

+53-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
import java.lang.invoke.MethodHandle;
77

8-
public class CompiledIRBlockBody extends IRBlockBody {
8+
import static org.jruby.runtime.Helpers.arrayOf;
9+
10+
public class CompiledIRBlockBody extends AbstractIRBlockBody {
911
protected final MethodHandle handle;
1012

1113
public CompiledIRBlockBody(MethodHandle handle, IRScope closure, long encodedSignature) {
@@ -30,6 +32,56 @@ public MethodHandle getHandle() {
3032
return handle;
3133
}
3234

35+
@Override
36+
public IRubyObject yield(ThreadContext context, Block block, IRubyObject value, IRubyObject self, Block blockArg) {
37+
return invokeYieldDirect(context, block, arrayOf(value), blockArg, self);
38+
}
39+
40+
@Override
41+
public IRubyObject yield(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
42+
return invokeYieldDirect(context, block, args, blockArg, self);
43+
}
44+
45+
@Override
46+
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, Block blockArg) {
47+
return invokeCallDirect(context, block, arrayOf(arg0), blockArg, null);
48+
}
49+
50+
@Override
51+
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, Block blockArg) {
52+
return invokeCallDirect(context, block, arrayOf(arg0, arg1), blockArg, null);
53+
}
54+
55+
@Override
56+
public IRubyObject call(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block blockArg) {
57+
return invokeCallDirect(context, block, arrayOf(arg0, arg1, arg2), blockArg, null);
58+
}
59+
60+
@Override
61+
public IRubyObject call(ThreadContext context, Block block, IRubyObject[] args, Block blockArg) {
62+
return invokeCallDirect(context, block, args, blockArg, null);
63+
}
64+
65+
@Override
66+
public IRubyObject yieldSpecific(ThreadContext context, Block block) {
67+
return invokeYieldDirect(context, block, null, Block.NULL_BLOCK, null);
68+
}
69+
70+
@Override
71+
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0) {
72+
return invokeYieldSpecificDirect(context, block, arg0, Block.NULL_BLOCK, null);
73+
}
74+
75+
@Override
76+
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1) {
77+
return invokeYieldSpecificDirect(context, block, arg0, arg1, Block.NULL_BLOCK, null);
78+
}
79+
80+
@Override
81+
public IRubyObject yieldSpecific(ThreadContext context, Block block, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
82+
return invokeYieldSpecificDirect(context, block, arg0, arg1, arg2, Block.NULL_BLOCK, null);
83+
}
84+
3385
@Override
3486
protected IRubyObject invokeCallDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
3587
context.setCurrentBlockType(Block.Type.PROC);
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,24 @@
11
package org.jruby.runtime;
22

33
import java.io.ByteArrayOutputStream;
4-
import org.jruby.RubyModule;
5-
import org.jruby.compiler.Compilable;
4+
65
import org.jruby.ir.IRClosure;
7-
import org.jruby.ir.IRScope;
86
import org.jruby.ir.interpreter.Interpreter;
97
import org.jruby.ir.interpreter.InterpreterContext;
108
import org.jruby.ir.persistence.IRDumper;
119
import org.jruby.ir.runtime.IRRuntimeHelpers;
1210
import org.jruby.runtime.builtin.IRubyObject;
13-
import org.jruby.util.cli.Options;
1411
import org.jruby.util.log.Logger;
1512
import org.jruby.util.log.LoggerFactory;
1613

17-
public class InterpretedIRBlockBody extends IRBlockBody implements Compilable<InterpreterContext> {
14+
public class InterpretedIRBlockBody extends AbstractIRBlockBody {
1815
private static final Logger LOG = LoggerFactory.getLogger(InterpretedIRBlockBody.class);
1916
protected boolean pushScope;
2017
protected boolean reuseParentScope;
21-
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG
22-
private int callCount = 0;
2318
private InterpreterContext interpreterContext;
24-
private InterpreterContext fullInterpreterContext;
2519

2620
public InterpretedIRBlockBody(IRClosure closure, Signature signature) {
2721
super(closure, signature);
28-
this.pushScope = true;
29-
this.reuseParentScope = false;
30-
31-
// JIT currently JITs blocks along with their method and no on-demand by themselves. We only
32-
// promote to full build here if we are -X-C.
33-
if (closure.getManager().getInstanceConfig().getCompileMode().shouldJIT() || Options.JIT_THRESHOLD.load() == -1) {
34-
callCount = -1;
35-
}
36-
}
37-
38-
@Override
39-
public void setCallCount(int callCount) {
40-
this.callCount = callCount;
41-
}
42-
43-
@Override
44-
public void completeBuild(InterpreterContext interpreterContext) {
45-
this.fullInterpreterContext = interpreterContext;
46-
// This enables IR & CFG to be dumped in debug mode
47-
// when this updated code starts executing.
48-
this.displayedCFG = false;
49-
}
50-
51-
@Override
52-
public IRScope getIRScope() {
53-
return closure;
5422
}
5523

5624
@Override
@@ -59,65 +27,47 @@ public ArgumentDescriptor[] getArgumentDescriptors() {
5927
}
6028

6129
public InterpreterContext ensureInstrsReady() {
62-
if (IRRuntimeHelpers.isDebug() && !displayedCFG) {
63-
LOG.info("Executing '" + closure + "' (pushScope=" + pushScope + ", reuseParentScope=" + reuseParentScope);
64-
LOG.info(closure.debugOutput());
65-
displayedCFG = true;
66-
}
30+
InterpreterContext interpreterContext = this.interpreterContext;
6731

6832
if (interpreterContext == null) {
33+
if (IRRuntimeHelpers.isDebug()) {
34+
LOG.info("Executing '" + closure + "' (pushScope=" + pushScope + ", reuseParentScope=" + reuseParentScope);
35+
LOG.info(closure.debugOutput());
36+
}
37+
6938
if (IRRuntimeHelpers.shouldPrintIR(closure.getStaticScope().getModule().getRuntime())) {
7039
ByteArrayOutputStream baos = IRDumper.printIR(closure, false);
7140

7241
LOG.info("Printing simple IR for " + closure.getName() + ":\n" + new String(baos.toByteArray()));
7342
}
7443

75-
interpreterContext = closure.getInterpreterContext();
76-
fullInterpreterContext = interpreterContext;
44+
interpreterContext = this.interpreterContext = closure.getInterpreterContext();
45+
this.pushScope = interpreterContext.pushNewDynScope();
46+
this.reuseParentScope = interpreterContext.reuseParentDynScope();
7747
}
78-
return interpreterContext;
79-
}
80-
81-
@Override
82-
public String getClassName(ThreadContext context) {
83-
return null;
84-
}
8548

86-
@Override
87-
public String getName() {
88-
return null;
49+
return interpreterContext;
8950
}
9051

9152
@Override
9253
public boolean canInvokeDirect() {
93-
return interpreterContext != null && interpreterContext.hasExplicitCallProtocol();
54+
return false;
9455
}
9556

9657
@Override
9758
protected IRubyObject invokeCallDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
98-
context.setCurrentBlockType(Block.Type.PROC);
99-
InterpreterContext ic = ensureInstrsReady(); // so we get debugging output
100-
return Interpreter.INTERPRET_BLOCK(context, block, null, ic, args, block.getBinding().getMethod(), blockArg);
59+
throw new UnsupportedOperationException("invokeCallDirect not implemented");
10160
}
10261

10362
@Override
10463
protected IRubyObject invokeYieldDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
105-
context.setCurrentBlockType(Block.Type.NORMAL);
106-
InterpreterContext ic = ensureInstrsReady(); // so we get debugging output
107-
return Interpreter.INTERPRET_BLOCK(context, block, self, ic, args, block.getBinding().getMethod(), blockArg);
64+
throw new UnsupportedOperationException("invokeYieldDirect not implemented");
10865
}
10966

11067
@Override
11168
protected IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
112-
if (callCount >= 0) promoteToFullBuild(context);
113-
11469
InterpreterContext ic = ensureInstrsReady();
11570

116-
// Update interpreter context for next time this block is executed
117-
// This ensures that if we had determined canInvokeDirect() is false
118-
// based on the old IC, we continue to execute with it.
119-
interpreterContext = fullInterpreterContext;
120-
12171
Binding binding = block.getBinding();
12272
Visibility oldVis = binding.getFrame().getVisibility();
12373
Frame prevFrame = context.preYieldNoScope(binding);
@@ -126,9 +76,9 @@ protected IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] a
12676
// probably points to the parent scope? To be verified and fixed if necessary. There is no harm as it is now. It
12777
// is just wasteful allocation since the scope is not used at all.
12878
DynamicScope actualScope = binding.getDynamicScope();
129-
if (ic.pushNewDynScope()) {
79+
if (pushScope) {
13080
context.pushScope(block.allocScope(actualScope));
131-
} else if (ic.reuseParentDynScope()) {
81+
} else if (reuseParentScope) {
13282
// Reuse! We can avoid the push only if surrounding vars aren't referenced!
13383
context.pushScope(actualScope);
13484
}
@@ -143,18 +93,4 @@ protected IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] a
14393
}
14494
}
14595

146-
// Unlike JIT in MixedMode this will always successfully build but if using executor pool it may take a while
147-
// and replace interpreterContext asynchronously.
148-
private void promoteToFullBuild(ThreadContext context) {
149-
if (context.runtime.isBooting() && !Options.JIT_KERNEL.load()) return; // don't Promote to full build during runtime boot
150-
151-
if (callCount++ >= Options.JIT_THRESHOLD.load()) {
152-
context.runtime.getJITCompiler().buildThresholdReached(context, this);
153-
}
154-
}
155-
156-
public RubyModule getImplementationClass() {
157-
return null;
158-
}
159-
16096
}

Diff for: ‎core/src/main/java/org/jruby/runtime/MixedModeIRBlockBody.java

+8-58
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,26 @@
55
import org.jruby.compiler.Compilable;
66
import org.jruby.ir.IRClosure;
77
import org.jruby.ir.IRScope;
8-
import org.jruby.ir.interpreter.Interpreter;
98
import org.jruby.ir.interpreter.InterpreterContext;
10-
import org.jruby.ir.persistence.IRDumper;
11-
import org.jruby.ir.runtime.IRRuntimeHelpers;
129
import org.jruby.runtime.builtin.IRubyObject;
1310
import org.jruby.util.cli.Options;
1411
import org.jruby.util.log.Logger;
1512
import org.jruby.util.log.LoggerFactory;
1613

17-
import java.io.ByteArrayOutputStream;
18-
19-
public class MixedModeIRBlockBody extends IRBlockBody implements Compilable<CompiledIRBlockBody> {
14+
public class MixedModeIRBlockBody extends AbstractIRBlockBody implements Compilable<AbstractIRBlockBody> {
2015
private static final Logger LOG = LoggerFactory.getLogger(MixedModeIRBlockBody.class);
2116

2217
protected boolean pushScope;
2318
protected boolean reuseParentScope;
24-
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG
2519
private volatile int callCount = 0;
26-
private InterpreterContext interpreterContext;
27-
private volatile CompiledIRBlockBody jittedBody;
20+
private final InterpretedIRBlockBody baseBody;
21+
private AbstractIRBlockBody jittedBody;
2822

2923
public MixedModeIRBlockBody(IRClosure closure, Signature signature) {
3024
super(closure, signature);
3125
this.pushScope = true;
3226
this.reuseParentScope = false;
27+
this.baseBody = new InterpretedIRBlockBody(closure, signature);
3328

3429
// JIT currently JITs blocks along with their method and no on-demand by themselves. We only
3530
// promote to full build here if we are -X-C.
@@ -47,7 +42,7 @@ public void setEvalType(EvalType evalType) {
4742

4843
@Override
4944
public boolean canInvokeDirect() {
50-
return jittedBody != null || (interpreterContext != null && interpreterContext.hasExplicitCallProtocol());
45+
return jittedBody != null;
5146
}
5247

5348
@Override
@@ -58,7 +53,7 @@ public void setCallCount(int callCount) {
5853
}
5954

6055
@Override
61-
public void completeBuild(CompiledIRBlockBody blockBody) {
56+
public void completeBuild(AbstractIRBlockBody blockBody) {
6257
setCallCount(-1);
6358
blockBody.evalType = this.evalType; // share with parent
6459
this.jittedBody = blockBody;
@@ -79,22 +74,7 @@ public ArgumentDescriptor[] getArgumentDescriptors() {
7974
}
8075

8176
public InterpreterContext ensureInstrsReady() {
82-
if (IRRuntimeHelpers.isDebug() && !displayedCFG) {
83-
LOG.info("Executing '" + closure + "' (pushScope=" + pushScope + ", reuseParentScope=" + reuseParentScope);
84-
LOG.info(closure.debugOutput());
85-
displayedCFG = true;
86-
}
87-
88-
if (interpreterContext == null) {
89-
if (IRRuntimeHelpers.shouldPrintIR(closure.getStaticScope().getModule().getRuntime())) {
90-
ByteArrayOutputStream baos = IRDumper.printIR(closure, false);
91-
92-
LOG.info("Printing simple IR for " + closure.getName() + ":\n" + new String(baos.toByteArray()));
93-
}
94-
95-
interpreterContext = closure.getInterpreterContext();
96-
}
97-
return interpreterContext;
77+
return baseBody.ensureInstrsReady();
9878
}
9979

10080
@Override
@@ -109,18 +89,12 @@ public String getName() {
10989

11090
@Override
11191
protected IRubyObject invokeCallDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
112-
// We should never get here if jittedBody is null
113-
assert jittedBody != null : "direct call in MixedModeIRBlockBody without jitted body";
114-
11592
context.setCurrentBlockType(Block.Type.PROC);
11693
return jittedBody.invokeCallDirect(context, block, args, blockArg, null);
11794
}
11895

11996
@Override
12097
protected IRubyObject invokeYieldDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
121-
// We should never get here if jittedBody is null
122-
assert jittedBody != null : "direct yield in MixedModeIRBlockBody without jitted body";
123-
12498
context.setCurrentBlockType(Block.Type.NORMAL);
12599
return jittedBody.invokeYieldDirect(context, block, args, blockArg, self);
126100
}
@@ -129,31 +103,7 @@ protected IRubyObject invokeYieldDirect(ThreadContext context, Block block, IRub
129103
protected IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
130104
if (callCount >= 0) promoteToFullBuild(context);
131105

132-
InterpreterContext ic = ensureInstrsReady();
133-
134-
Binding binding = block.getBinding();
135-
Visibility oldVis = binding.getFrame().getVisibility();
136-
Frame prevFrame = context.preYieldNoScope(binding);
137-
138-
// SSS FIXME: Maybe, we should allocate a NoVarsScope/DummyScope for for-loop bodies because the static-scope here
139-
// probably points to the parent scope? To be verified and fixed if necessary. There is no harm as it is now. It
140-
// is just wasteful allocation since the scope is not used at all.
141-
DynamicScope actualScope = binding.getDynamicScope();
142-
if (ic.pushNewDynScope()) {
143-
context.pushScope(block.allocScope(actualScope));
144-
} else if (ic.reuseParentDynScope()) {
145-
// Reuse! We can avoid the push only if surrounding vars aren't referenced!
146-
context.pushScope(actualScope);
147-
}
148-
149-
self = IRRuntimeHelpers.updateBlockState(block, self);
150-
151-
try {
152-
return Interpreter.INTERPRET_BLOCK(context, block, self, ic, args, binding.getMethod(), blockArg);
153-
}
154-
finally {
155-
postYield(context, ic, binding, oldVis, prevFrame);
156-
}
106+
return baseBody.invoke(context, block, args, blockArg, self);
157107
}
158108

159109
private void promoteToFullBuild(ThreadContext context) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.jruby.runtime;
2+
3+
import org.jruby.ir.IRClosure;
4+
import org.jruby.ir.interpreter.Interpreter;
5+
import org.jruby.ir.interpreter.InterpreterContext;
6+
import org.jruby.runtime.builtin.IRubyObject;
7+
import org.jruby.util.log.Logger;
8+
import org.jruby.util.log.LoggerFactory;
9+
10+
public class OptInterpretedIRBlockBody extends AbstractIRBlockBody {
11+
private static final Logger LOG = LoggerFactory.getLogger(OptInterpretedIRBlockBody.class);
12+
protected boolean pushScope;
13+
protected boolean reuseParentScope;
14+
private InterpreterContext fullInterpreterContext;
15+
16+
public OptInterpretedIRBlockBody(IRClosure closure, Signature signature) {
17+
super(closure, signature);
18+
this.pushScope = true;
19+
this.reuseParentScope = false;
20+
this.fullInterpreterContext = closure.prepareFullBuild();
21+
}
22+
23+
@Override
24+
public ArgumentDescriptor[] getArgumentDescriptors() {
25+
return closure.getArgumentDescriptors();
26+
}
27+
28+
@Override
29+
public boolean canInvokeDirect() {
30+
return true;
31+
}
32+
33+
@Override
34+
protected IRubyObject invokeCallDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
35+
context.setCurrentBlockType(Block.Type.PROC);
36+
InterpreterContext ic = fullInterpreterContext;
37+
return Interpreter.INTERPRET_BLOCK(context, block, null, ic, args, block.getBinding().getMethod(), blockArg);
38+
}
39+
40+
@Override
41+
protected IRubyObject invokeYieldDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
42+
context.setCurrentBlockType(Block.Type.NORMAL);
43+
InterpreterContext ic = fullInterpreterContext;
44+
return Interpreter.INTERPRET_BLOCK(context, block, self, ic, args, block.getBinding().getMethod(), blockArg);
45+
}
46+
47+
@Override
48+
protected IRubyObject invoke(ThreadContext context, Block block, IRubyObject[] args, Block blockArg, IRubyObject self) {
49+
throw new UnsupportedOperationException("invoke not implemented");
50+
}
51+
52+
}

Diff for: ‎core/src/main/java/org/jruby/runtime/backtrace/FrameType.java

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.jruby.internal.runtime.methods.InterpretedIRBodyMethod;
66
import org.jruby.internal.runtime.methods.InterpretedIRMethod;
77
import org.jruby.internal.runtime.methods.MixedModeIRMethod;
8+
import org.jruby.internal.runtime.methods.OptInterpretedIRMethod;
89
import org.jruby.ir.interpreter.Interpreter;
910

1011
public enum FrameType {
@@ -16,6 +17,7 @@ public enum FrameType {
1617
INTERPRETED_CLASSES.add(Interpreter.class.getName());
1718
INTERPRETED_CLASSES.add(MixedModeIRMethod.class.getName());
1819
INTERPRETED_CLASSES.add(InterpretedIRMethod.class.getName());
20+
INTERPRETED_CLASSES.add(OptInterpretedIRMethod.class.getName());
1921
INTERPRETED_CLASSES.add(InterpretedIRBodyMethod.class.getName());
2022
}
2123

0 commit comments

Comments
 (0)
Please sign in to comment.