-
-
Notifications
You must be signed in to change notification settings - Fork 925
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into truffle-head
Conflicts: truffle/src/main/java/org/jruby/truffle/nodes/core/HashNodes.java truffle/src/main/java/org/jruby/truffle/nodes/yield/UninitializedYieldDispatchNode.java
- 9.4.12.0
- 9.4.11.0
- 9.4.10.0
- 9.4.9.0
- 9.4.8.0
- 9.4.7.0
- 9.4.6.0
- 9.4.5.0
- 9.4.4.0
- 9.4.3.0
- 9.4.2.0
- 9.4.1.0
- 9.4.0.0
- 9.3.15.0
- 9.3.14.0
- 9.3.13.0
- 9.3.12.0
- 9.3.11.0
- 9.3.10.0
- 9.3.9.0
- 9.3.8.0
- 9.3.7.0
- 9.3.6.0
- 9.3.5.0
- 9.3.4.0
- 9.3.3.0
- 9.3.2.0
- 9.3.1.0
- 9.3.0.0
- 9.2.21.0
- 9.2.20.1
- 9.2.20.0
- 9.2.19.0
- 9.2.18.0
- 9.2.17.0
- 9.2.16.0
- 9.2.15.0
- 9.2.14.0
- 9.2.13.0
- 9.2.12.0
- 9.2.11.1
- 9.2.11.0
- 9.2.10.0
- 9.2.9.0
- 9.2.8.0
- 9.2.7.0
- 9.2.6.0
- 9.2.5.0
- 9.2.4.1
- 9.2.4.0
- 9.2.3.0
- 9.2.2.0
- 9.2.1.0
- 9.2.0.0
- 9.1.17.0
- 9.1.16.0
- 9.1.15.0
- 9.1.14.0
- 9.1.13.0
- 9.1.12.0
- 9.1.11.0
- 9.1.10.0
- 9.1.9.0
- 9.1.8.0
- 9.1.7.0
- 9.1.6.0
- 9.1.5.0
- 9.1.4.0
- 9.1.3.0
- 9.1.2.0
- 9.1.1.0
- 9.1.0.0
- 9.0.5.0
- 9.0.4.0
- 9.0.3.0
- 9.0.1.0
- 9.0.0.0
- 9.0.0.0.rc2
- 9.0.0.0.rc1
Showing
214 changed files
with
2,938 additions
and
2,022 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
core/src/main/java/org/jruby/compiler/FullBuildSource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.jruby.compiler; | ||
|
||
import org.jruby.RubyModule; | ||
import org.jruby.ir.IRScope; | ||
import org.jruby.ir.interpreter.InterpreterContext; | ||
|
||
/** | ||
* Blocks and methods both share same full build mechanism so they implement this to be buildable. | ||
*/ | ||
public interface FullBuildSource { | ||
public void setCallCount(int count); | ||
public void switchToFullBuild(InterpreterContext interpreterContext); | ||
public IRScope getIRScope(); | ||
public InterpreterContext ensureInstrsReady(); | ||
public String getName(); | ||
public String getFile(); | ||
public int getLine(); | ||
public RubyModule getImplementationClass(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
202 changes: 58 additions & 144 deletions
202
core/src/main/java/org/jruby/internal/runtime/methods/InterpretedIRMethod.java
Large diffs are not rendered by default.
Oops, something went wrong.
369 changes: 369 additions & 0 deletions
369
core/src/main/java/org/jruby/internal/runtime/methods/MixedModeIRMethod.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,369 @@ | ||
package org.jruby.internal.runtime.methods; | ||
|
||
import java.util.List; | ||
|
||
import org.jruby.MetaClass; | ||
import org.jruby.Ruby; | ||
import org.jruby.RubyClass; | ||
import org.jruby.RubyModule; | ||
import org.jruby.ir.*; | ||
import org.jruby.ir.interpreter.InterpreterContext; | ||
import org.jruby.ir.runtime.IRRuntimeHelpers; | ||
import org.jruby.parser.StaticScope; | ||
import org.jruby.runtime.Arity; | ||
import org.jruby.runtime.Block; | ||
import org.jruby.runtime.DynamicScope; | ||
import org.jruby.runtime.PositionAware; | ||
import org.jruby.runtime.ThreadContext; | ||
import org.jruby.runtime.Visibility; | ||
import org.jruby.runtime.builtin.IRubyObject; | ||
import org.jruby.util.cli.Options; | ||
import org.jruby.util.log.Logger; | ||
import org.jruby.util.log.LoggerFactory; | ||
|
||
public class MixedModeIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware { | ||
private static final Logger LOG = LoggerFactory.getLogger("InterpretedIRMethod"); | ||
|
||
private Arity arity; | ||
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG | ||
|
||
protected final IRScope method; | ||
|
||
protected static class DynamicMethodBox { | ||
public DynamicMethod actualMethod; | ||
public int callCount = 0; | ||
} | ||
|
||
protected DynamicMethodBox box = new DynamicMethodBox(); | ||
|
||
public MixedModeIRMethod(IRScope method, Visibility visibility, RubyModule implementationClass) { | ||
super(implementationClass, visibility, CallConfiguration.FrameNoneScopeNone, method.getName()); | ||
this.method = method; | ||
this.method.getStaticScope().determineModule(); | ||
this.arity = calculateArity(); | ||
|
||
// disable JIT if JIT is disabled | ||
// FIXME: kinda hacky, but I use IRMethod data in JITCompiler. | ||
if (!implementationClass.getRuntime().getInstanceConfig().getCompileMode().shouldJIT()) { | ||
this.box.callCount = -1; | ||
} | ||
} | ||
|
||
public IRScope getIRMethod() { | ||
return method; | ||
} | ||
|
||
public DynamicMethod getActualMethod() { | ||
return box.actualMethod; | ||
} | ||
|
||
public void setCallCount(int callCount) { | ||
box.callCount = callCount; | ||
} | ||
|
||
public StaticScope getStaticScope() { | ||
return method.getStaticScope(); | ||
} | ||
|
||
public String[] getParameterList() { | ||
ensureInstrsReady(); // Make sure method is minimally built before returning this info | ||
return ((IRMethod) method).getArgDesc(); | ||
} | ||
|
||
private Arity calculateArity() { | ||
StaticScope s = method.getStaticScope(); | ||
if (s.getOptionalArgs() > 0 || s.getRestArg() >= 0) return Arity.required(s.getRequiredArgs()); | ||
|
||
return Arity.createArity(s.getRequiredArgs()); | ||
} | ||
|
||
@Override | ||
public Arity getArity() { | ||
return this.arity; | ||
} | ||
|
||
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, RubyModule implClass) { | ||
// update call stacks (push: frame, class, scope, etc.) | ||
context.preMethodFrameOnly(implClass, name, self, block); | ||
if (ic.pushNewDynScope()) { | ||
context.pushScope(DynamicScope.newDynamicScope(ic.getStaticScope())); | ||
} | ||
context.setCurrentVisibility(getVisibility()); | ||
} | ||
|
||
// FIXME: for subclasses we should override this method since it can be simple get | ||
// FIXME: to avoid cost of synch call in lazilyacquire we can save the ic here | ||
public InterpreterContext ensureInstrsReady() { | ||
if (method instanceof IRMethod) { | ||
return ((IRMethod) method).lazilyAcquireInterpreterContext(); | ||
} | ||
return method.getInterpreterContext(); | ||
} | ||
|
||
@Override | ||
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) { | ||
if (IRRuntimeHelpers.isDebug()) doDebug(); | ||
|
||
DynamicMethodBox box = this.box; | ||
if (box.callCount >= 0) tryJit(context, box); | ||
DynamicMethod jittedMethod = box.actualMethod; | ||
|
||
if (jittedMethod != null) { | ||
return jittedMethod.call(context, self, clazz, name, args, block); | ||
} else { | ||
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, args, block); | ||
} | ||
} | ||
|
||
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass, | ||
IRubyObject self, String name, IRubyObject[] args, Block block) { | ||
try { | ||
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine()); | ||
|
||
if (ic.hasExplicitCallProtocol()) { | ||
return ic.engine.interpret(context, self, ic, implClass, name, args, block, null); | ||
} else { | ||
try { | ||
this.pre(ic, context, self, name, block, implClass); | ||
return ic.engine.interpret(context, self, ic, implClass, name, args, block, null); | ||
} finally { | ||
this.post(ic, context); | ||
} | ||
} | ||
} finally { | ||
ThreadContext.popBacktrace(context); | ||
} | ||
} | ||
|
||
@Override | ||
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) { | ||
if (IRRuntimeHelpers.isDebug()) doDebug(); | ||
|
||
DynamicMethodBox box = this.box; | ||
if (box.callCount >= 0) tryJit(context, box); | ||
DynamicMethod jittedMethod = box.actualMethod; | ||
|
||
if (jittedMethod != null) { | ||
return jittedMethod.call(context, self, clazz, name, block); | ||
} else { | ||
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, block); | ||
} | ||
} | ||
|
||
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass, | ||
IRubyObject self, String name, Block block) { | ||
try { | ||
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine()); | ||
|
||
if (ic.hasExplicitCallProtocol()) { | ||
return ic.engine.interpret(context, self, ic, implClass, name, block, null); | ||
} else { | ||
try { | ||
this.pre(ic, context, self, name, block, implClass); | ||
return ic.engine.interpret(context, self, ic, implClass, name, block, null); | ||
} finally { | ||
this.post(ic, context); | ||
} | ||
} | ||
} finally { | ||
ThreadContext.popBacktrace(context); | ||
} | ||
} | ||
|
||
@Override | ||
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) { | ||
if (IRRuntimeHelpers.isDebug()) doDebug(); | ||
|
||
DynamicMethodBox box = this.box; | ||
if (box.callCount >= 0) tryJit(context, box); | ||
DynamicMethod jittedMethod = box.actualMethod; | ||
|
||
if (jittedMethod != null) { | ||
return jittedMethod.call(context, self, clazz, name, arg0, block); | ||
} else { | ||
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, arg0, block); | ||
} | ||
} | ||
|
||
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass, | ||
IRubyObject self, String name, IRubyObject arg1, Block block) { | ||
try { | ||
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine()); | ||
|
||
if (ic.hasExplicitCallProtocol()) { | ||
return ic.engine.interpret(context, self, ic, implClass, name, arg1, block, null); | ||
} else { | ||
try { | ||
this.pre(ic, context, self, name, block, implClass); | ||
return ic.engine.interpret(context, self, ic, implClass, name, arg1, block, null); | ||
} finally { | ||
this.post(ic, context); | ||
} | ||
} | ||
} finally { | ||
ThreadContext.popBacktrace(context); | ||
} | ||
} | ||
|
||
@Override | ||
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) { | ||
if (IRRuntimeHelpers.isDebug()) doDebug(); | ||
|
||
DynamicMethodBox box = this.box; | ||
if (box.callCount >= 0) tryJit(context, box); | ||
DynamicMethod jittedMethod = box.actualMethod; | ||
|
||
if (jittedMethod != null) { | ||
return jittedMethod.call(context, self, clazz, name, arg0, arg1, block); | ||
} else { | ||
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, arg0, arg1, block); | ||
} | ||
} | ||
|
||
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass, | ||
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, Block block) { | ||
try { | ||
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine()); | ||
|
||
if (ic.hasExplicitCallProtocol()) { | ||
return ic.engine.interpret(context, self, ic, implClass, name, arg1, arg2, block, null); | ||
} else { | ||
try { | ||
this.pre(ic, context, self, name, block, implClass); | ||
return ic.engine.interpret(context, self, ic, implClass, name, arg1, arg2, block, null); | ||
} finally { | ||
this.post(ic, context); | ||
} | ||
} | ||
} finally { | ||
ThreadContext.popBacktrace(context); | ||
} | ||
} | ||
|
||
@Override | ||
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) { | ||
if (IRRuntimeHelpers.isDebug()) doDebug(); | ||
|
||
DynamicMethodBox box = this.box; | ||
if (box.callCount >= 0) tryJit(context, box); | ||
DynamicMethod jittedMethod = box.actualMethod; | ||
|
||
if (jittedMethod != null) { | ||
return jittedMethod.call(context, self, clazz, name, arg0, arg1, arg2, block); | ||
} else { | ||
return INTERPRET_METHOD(context, ensureInstrsReady(), getImplementationClass().getMethodLocation(), self, name, arg0, arg1, arg2, block); | ||
} | ||
} | ||
|
||
private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext ic, RubyModule implClass, | ||
IRubyObject self, String name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, Block block) { | ||
try { | ||
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine()); | ||
|
||
if (ic.hasExplicitCallProtocol()) { | ||
return ic.engine.interpret(context, self, ic, implClass, name, arg1, arg2, arg3, block, null); | ||
} else { | ||
try { | ||
this.pre(ic, context, self, name, block, implClass); | ||
return ic.engine.interpret(context, self, ic, implClass, name, arg1, arg2, arg3, block, null); | ||
} finally { | ||
this.post(ic, context); | ||
} | ||
} | ||
} finally { | ||
ThreadContext.popBacktrace(context); | ||
} | ||
|
||
} | ||
|
||
protected void doDebug() { | ||
// FIXME: This is printing out IRScope CFG but JIT may be active and it might not reflect | ||
// currently executing. Move into JIT and into interp since they will be getting CFG from | ||
// different sources | ||
// FIXME: This is only printing out CFG once. If we keep applying more passes then we | ||
// will want to print out after those new passes. | ||
ensureInstrsReady(); | ||
LOG.info("Executing '" + method.getName() + "'"); | ||
if (!displayedCFG) { | ||
LOG.info(method.debugOutput()); | ||
displayedCFG = true; | ||
} | ||
} | ||
|
||
public DynamicMethod getMethodForCaching() { | ||
DynamicMethod method = box.actualMethod; | ||
if (method instanceof CompiledIRMethod) { | ||
return method; | ||
} | ||
return this; | ||
} | ||
|
||
public void switchToJitted(CompiledIRMethod newMethod) { | ||
this.box.actualMethod = newMethod; | ||
this.box.actualMethod.serialNumber = this.serialNumber; | ||
this.box.callCount = -1; | ||
getImplementationClass().invalidateCacheDescendants(); | ||
} | ||
|
||
|
||
protected void tryJit(ThreadContext context, DynamicMethodBox box) { | ||
Ruby runtime = context.runtime; | ||
|
||
// don't JIT during runtime boot | ||
if (runtime.isBooting()) return; | ||
|
||
String className; | ||
if (implementationClass.isSingleton()) { | ||
MetaClass metaClass = (MetaClass)implementationClass; | ||
RubyClass realClass = metaClass.getRealClass(); | ||
// if real class is Class | ||
if (realClass == context.runtime.getClassClass()) { | ||
// use the attached class's name | ||
className = ((RubyClass)metaClass.getAttached()).getName(); | ||
} else { | ||
// use the real class name | ||
className = realClass.getName(); | ||
} | ||
} else { | ||
// use the class name | ||
className = implementationClass.getName(); | ||
} | ||
|
||
|
||
if (box.callCount++ >= Options.JIT_THRESHOLD.load()) { | ||
context.runtime.getJITCompiler().jitThresholdReached(this, context.runtime.getInstanceConfig(), context, className, name); | ||
} | ||
} | ||
|
||
public void setActualMethod(CompiledIRMethod method) { | ||
this.box.actualMethod = method; | ||
} | ||
|
||
protected void dupBox(MixedModeIRMethod orig) { | ||
this.box = orig.box; | ||
} | ||
|
||
@Override | ||
public DynamicMethod dup() { | ||
MixedModeIRMethod x = new MixedModeIRMethod(method, visibility, implementationClass); | ||
x.box = box; | ||
|
||
return x; | ||
} | ||
|
||
public String getFile() { | ||
return method.getFileName(); | ||
} | ||
|
||
public int getLine() { | ||
return method.getLineNumber(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 0 additions & 13 deletions
13
core/src/main/java/org/jruby/ir/dataflow/DataFlowConstants.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 0 additions & 2 deletions
2
core/src/main/java/org/jruby/ir/dataflow/analyses/LiveVariableNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 172 additions & 0 deletions
172
core/src/main/java/org/jruby/ir/interpreter/FullInterpreterContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
package org.jruby.ir.interpreter; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import org.jruby.ir.IRFlags; | ||
import org.jruby.ir.IRMethod; | ||
import org.jruby.ir.IRScope; | ||
import org.jruby.ir.dataflow.DataFlowProblem; | ||
import org.jruby.ir.instructions.Instr; | ||
import org.jruby.ir.instructions.ReceiveSelfInstr; | ||
import org.jruby.ir.passes.CompilerPass; | ||
import org.jruby.ir.representations.BasicBlock; | ||
import org.jruby.ir.representations.CFG; | ||
import org.jruby.ir.representations.CFGLinearizer; | ||
|
||
/** | ||
* Created by enebo on 2/27/15. | ||
*/ | ||
public class FullInterpreterContext extends InterpreterContext { | ||
private CFG cfg; | ||
|
||
// Creation of this field will happen in generateInstructionsForInterpretation or during IRScope.prepareForInitialCompilation. | ||
// FIXME: At some point when we relinearize after running another phase of passes we should document that here to know how this field is changed | ||
private BasicBlock[] linearizedBBList = null; | ||
|
||
/** Map of name -> dataflow problem */ | ||
private Map<String, DataFlowProblem> dataFlowProblems; | ||
|
||
/** What passes have been run on this scope? */ | ||
private List<CompilerPass> executedPasses = new ArrayList<>(); | ||
|
||
// FIXME: Perhaps abstract IC into interface of base class so we do not have a null instructions field here | ||
public FullInterpreterContext(IRScope scope, Instr[] instructions) { | ||
super(scope, null); | ||
|
||
cfg = buildCFG(instructions); | ||
} | ||
|
||
/** | ||
* have this interpretercontext fully built? This is slightly more complicated than this simple check, but it | ||
* should work. In -X-C full builds we linearize at the beginning of our generateInstructionsForIntepretation | ||
* method. Last thing we do essentially is set instructions to be something. For JIT builds last thing we | ||
* need to check is whether we have linearized the BB list. | ||
*/ | ||
@Override | ||
public boolean buildComplete() { | ||
return linearizedBBList != null; | ||
} | ||
|
||
public BasicBlock[] linearizeBasicBlocks() { | ||
linearizedBBList = CFGLinearizer.linearize(cfg); | ||
return linearizedBBList; | ||
} | ||
|
||
private CFG buildCFG(Instr[] instructions) { | ||
CFG newCFG = new CFG(getScope()); | ||
|
||
newCFG.build(instructions); | ||
|
||
return newCFG; | ||
} | ||
|
||
@Override | ||
public boolean hasExplicitCallProtocol() { | ||
return getScope().getFlags().contains(IRFlags.HAS_EXPLICIT_CALL_PROTOCOL); | ||
} | ||
|
||
@Override | ||
public boolean pushNewDynScope() { | ||
return !getScope().getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED) && !reuseParentDynScope(); | ||
} | ||
|
||
@Override | ||
public boolean popDynScope() { | ||
return pushNewDynScope() || reuseParentDynScope(); | ||
} | ||
|
||
@Override | ||
public boolean reuseParentDynScope() { | ||
return getScope().getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE); | ||
} | ||
|
||
/** We plan on running this in full interpreted mode. This will fixup ipc, rpc, and generate instr list */ | ||
public void generateInstructionsForIntepretation() { | ||
linearizeBasicBlocks(); | ||
boolean simple_method = getScope() instanceof IRMethod; | ||
|
||
// Pass 1. Set up IPCs for labels and instructions and build linear instr list | ||
List<Instr> newInstrs = new ArrayList<>(); | ||
int ipc = 0; | ||
for (BasicBlock b: getLinearizedBBList()) { | ||
// All same-named labels must be same Java instance for this to work or we would need | ||
// to examine all Label operands and update this as well which would be expensive. | ||
b.getLabel().setTargetPC(ipc); | ||
|
||
List<Instr> bbInstrs = b.getInstrs(); | ||
int bbInstrsLength = bbInstrs.size(); | ||
// FIXME: Can be replaced with System.arrayCopy to avoid call newInstrs.add a zillion times | ||
for (int i = 0; i < bbInstrsLength; i++) { | ||
Instr instr = bbInstrs.get(i); | ||
if (simple_method && SimpleMethodInterpreterEngine.OPERATIONS.get(instr.getOperation()) == null) simple_method = false; | ||
if (!(instr instanceof ReceiveSelfInstr)) { | ||
instr.setIPC(ipc); | ||
newInstrs.add(instr); | ||
ipc++; | ||
} | ||
} | ||
} | ||
|
||
if (simple_method) getScope().getFlags().add(IRFlags.SIMPLE_METHOD); | ||
|
||
cfg.getExitBB().getLabel().setTargetPC(ipc + 1); // Exit BB ipc | ||
|
||
Instr[] linearizedInstrArray = newInstrs.toArray(new Instr[newInstrs.size()]); | ||
|
||
// Pass 2: Use ipc info from previous to mark all linearized instrs rpc | ||
ipc = 0; | ||
for (BasicBlock b : getLinearizedBBList()) { | ||
BasicBlock rescuerBB = cfg.getRescuerBBFor(b); | ||
int rescuerPC = rescuerBB == null ? -1 : rescuerBB.getLabel().getTargetPC(); | ||
for (Instr instr : b.getInstrs()) { | ||
// FIXME: If we did not omit instrs from previous pass, we could end up just doing | ||
// a size and for loop this n times instead of walking an examining each instr | ||
if (!(instr instanceof ReceiveSelfInstr)) { | ||
linearizedInstrArray[ipc].setRPC(rescuerPC); | ||
ipc++; | ||
} | ||
} | ||
} | ||
|
||
instructions = linearizedInstrArray; | ||
temporaryVariablecount = getScope().getTemporaryVariablesCount(); | ||
|
||
// System.out.println("SCOPE: " + getScope().getName()); | ||
// System.out.println("INSTRS: " + cfg.toStringInstrs()); | ||
} | ||
|
||
@Override | ||
public CFG getCFG() { | ||
return cfg; | ||
} | ||
|
||
@Override | ||
public void computeScopeFlagsFromInstructions() { | ||
for (BasicBlock b: cfg.getBasicBlocks()) { | ||
for (Instr i: b.getInstrs()) { | ||
i.computeScopeFlags(getScope()); | ||
} | ||
} | ||
} | ||
|
||
public Map<String, DataFlowProblem> getDataFlowProblems() { | ||
if (dataFlowProblems == null) dataFlowProblems = new HashMap<>(); | ||
return dataFlowProblems; | ||
} | ||
|
||
public List<CompilerPass> getExecutedPasses() { | ||
return executedPasses; | ||
} | ||
|
||
// FIXME: Potentially remove | ||
public BasicBlock[] getLinearizedBBList() { | ||
return linearizedBBList; | ||
} | ||
|
||
@Override | ||
public String toStringInstrs() { | ||
return "\nCFG:\n" + cfg.toStringGraph() + "\nInstructions:\n" + cfg.toStringInstrs(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
core/src/main/java/org/jruby/ir/interpreter/StartupInterpreterEngine.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
package org.jruby.ir.interpreter; | ||
|
||
import java.util.Stack; | ||
import org.jruby.RubyModule; | ||
import org.jruby.common.IRubyWarnings; | ||
import org.jruby.ir.IRScope; | ||
import org.jruby.ir.Operation; | ||
import org.jruby.ir.instructions.BreakInstr; | ||
import org.jruby.ir.instructions.CheckForLJEInstr; | ||
import org.jruby.ir.instructions.CopyInstr; | ||
import org.jruby.ir.instructions.GetFieldInstr; | ||
import org.jruby.ir.instructions.Instr; | ||
import org.jruby.ir.instructions.JumpInstr; | ||
import org.jruby.ir.instructions.NonlocalReturnInstr; | ||
import org.jruby.ir.instructions.RuntimeHelperCall; | ||
import org.jruby.ir.instructions.SearchConstInstr; | ||
import org.jruby.ir.runtime.IRBreakJump; | ||
import org.jruby.ir.runtime.IRReturnJump; | ||
import org.jruby.ir.runtime.IRRuntimeHelpers; | ||
import org.jruby.parser.StaticScope; | ||
import org.jruby.runtime.Block; | ||
import org.jruby.runtime.DynamicScope; | ||
import org.jruby.runtime.Helpers; | ||
import org.jruby.runtime.ThreadContext; | ||
import org.jruby.runtime.builtin.IRubyObject; | ||
import org.jruby.runtime.ivars.VariableAccessor; | ||
import org.jruby.runtime.opto.ConstantCache; | ||
|
||
/** | ||
* This interpreter is meant to interpret the instructions generated directly from IRBuild. | ||
*/ | ||
public class StartupInterpreterEngine extends InterpreterEngine { | ||
public IRubyObject interpret(ThreadContext context, IRubyObject self, | ||
InterpreterContext interpreterContext, RubyModule implClass, | ||
String name, IRubyObject[] args, Block block, Block.Type blockType) { | ||
Instr[] instrs = interpreterContext.getInstructions(); | ||
Object[] temp = interpreterContext.allocateTemporaryVariables(); | ||
int n = instrs.length; | ||
int ipc = 0; | ||
Object exception = null; | ||
|
||
StaticScope currScope = interpreterContext.getStaticScope(); | ||
DynamicScope currDynScope = context.getCurrentScope(); | ||
IRScope scope = currScope.getIRScope(); | ||
boolean acceptsKeywordArgument = interpreterContext.receivesKeywordArguments(); | ||
|
||
Stack<Integer> rescuePCs = new Stack<>(); | ||
|
||
// Init profiling this scope | ||
boolean debug = IRRuntimeHelpers.isDebug(); | ||
boolean profile = IRRuntimeHelpers.inProfileMode(); | ||
Integer scopeVersion = profile ? Profiler.initProfiling(scope) : 0; | ||
|
||
// Enter the looooop! | ||
while (ipc < n) { | ||
Instr instr = instrs[ipc]; | ||
ipc++; | ||
Operation operation = instr.getOperation(); | ||
if (debug) { | ||
Interpreter.LOG.info("I: {}", instr); | ||
Interpreter.interpInstrsCount++; | ||
} else if (profile) { | ||
Profiler.instrTick(operation); | ||
Interpreter.interpInstrsCount++; | ||
} | ||
|
||
try { | ||
switch (operation.opClass) { | ||
case ARG_OP: | ||
receiveArg(context, instr, operation, args, acceptsKeywordArgument, currDynScope, temp, exception, block); | ||
break; | ||
case CALL_OP: | ||
if (profile) Profiler.updateCallSite(instr, scope, scopeVersion); | ||
processCall(context, instr, operation, currDynScope, currScope, temp, self); | ||
break; | ||
case RET_OP: | ||
return processReturnOp(context, instr, operation, currDynScope, temp, self, blockType, currScope); | ||
case BRANCH_OP: | ||
switch (operation) { | ||
case JUMP: ipc = ((JumpInstr)instr).getJumpTarget().getTargetPC(); break; | ||
default: ipc = instr.interpretAndGetNewIPC(context, currDynScope, currScope, self, temp, ipc); break; | ||
} | ||
break; | ||
case BOOK_KEEPING_OP: | ||
if (operation == Operation.PUSH_BINDING) { | ||
// IMPORTANT: Preserve this update of currDynScope. | ||
// This affects execution of all instructions in this scope | ||
// which will now use the updated value of currDynScope. | ||
currDynScope = interpreterContext.newDynamicScope(context); | ||
context.pushScope(currDynScope); | ||
} else { | ||
processBookKeepingOp(context, instr, operation, name, args, self, block, implClass, rescuePCs); | ||
} | ||
break; | ||
case OTHER_OP: | ||
processOtherOp(context, instr, operation, currDynScope, currScope, temp, self, blockType); | ||
break; | ||
} | ||
} catch (Throwable t) { | ||
if (debug) extractToMethodToAvoidC2Crash(instr, t); | ||
|
||
if (rescuePCs.empty() || (t instanceof IRBreakJump && instr instanceof BreakInstr) || | ||
(t instanceof IRReturnJump && instr instanceof NonlocalReturnInstr)) { | ||
ipc = -1; | ||
} else { | ||
ipc = rescuePCs.pop(); | ||
} | ||
|
||
if (debug) { | ||
Interpreter.LOG.info("in : " + interpreterContext.getStaticScope().getIRScope() + ", caught Java throwable: " + t + "; excepting instr: " + instr); | ||
Interpreter.LOG.info("ipc for rescuer: " + ipc); | ||
} | ||
|
||
if (ipc == -1) { | ||
Helpers.throwException(t); | ||
} else { | ||
exception = t; | ||
} | ||
} | ||
} | ||
|
||
// Control should never get here! | ||
throw context.runtime.newRuntimeError("BUG: interpreter fell through to end unexpectedly"); | ||
} | ||
|
||
protected static void processOtherOp(ThreadContext context, Instr instr, Operation operation, DynamicScope currDynScope, | ||
StaticScope currScope, Object[] temp, IRubyObject self, Block.Type blockType) { | ||
switch(operation) { | ||
case RECV_SELF: | ||
break; | ||
case COPY: { | ||
CopyInstr c = (CopyInstr)instr; | ||
setResult(temp, currDynScope, c.getResult(), retrieveOp(c.getSource(), context, self, currDynScope, currScope, temp)); | ||
break; | ||
} | ||
case GET_FIELD: { | ||
GetFieldInstr gfi = (GetFieldInstr)instr; | ||
IRubyObject object = (IRubyObject)gfi.getSource().retrieve(context, self, currScope, currDynScope, temp); | ||
VariableAccessor a = gfi.getAccessor(object); | ||
Object result = a == null ? null : (IRubyObject)a.get(object); | ||
if (result == null) { | ||
if (context.runtime.isVerbose()) { | ||
context.runtime.getWarnings().warning(IRubyWarnings.ID.IVAR_NOT_INITIALIZED, "instance variable " + gfi.getRef() + " not initialized"); | ||
} | ||
result = context.nil; | ||
} | ||
setResult(temp, currDynScope, gfi.getResult(), result); | ||
break; | ||
} | ||
case SEARCH_CONST: { | ||
SearchConstInstr sci = (SearchConstInstr)instr; | ||
ConstantCache cache = sci.getConstantCache(); | ||
Object result = !ConstantCache.isCached(cache) ? | ||
sci.cache(context, currScope, currDynScope, self, temp) : cache.value; | ||
setResult(temp, currDynScope, sci.getResult(), result); | ||
break; | ||
} | ||
case RUNTIME_HELPER: { | ||
RuntimeHelperCall rhc = (RuntimeHelperCall)instr; | ||
setResult(temp, currDynScope, rhc.getResult(), | ||
rhc.callHelper(context, currScope, currDynScope, self, temp, blockType)); | ||
break; | ||
} | ||
case CHECK_FOR_LJE: | ||
((CheckForLJEInstr) instr).check(context, currDynScope, blockType); | ||
break; | ||
case LOAD_FRAME_CLOSURE: | ||
setResult(temp, currDynScope, instr, context.getFrameBlock()); | ||
return; | ||
// ---------- All the rest --------- | ||
default: | ||
setResult(temp, currDynScope, instr, instr.interpret(context, currScope, currDynScope, self, temp)); | ||
break; | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.