Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 851477a429de
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a1e06a27f544
Choose a head ref
  • 2 commits
  • 9 files changed
  • 1 contributor

Commits on May 15, 2015

  1. push IRScope to base class for block bodies (will make it easier to c…

    …onvert blocks in define_method to full methods later)
    enebo committed May 15, 2015
    Copy the full SHA
    22e2ed7 View commit details
  2. Combine full build and JIT executor code. This will help prevent chan…

    …ges over time of having two
    
    code paths (this combination fixed -X-C to honor no background building it jit.threshold=0).
    enebo committed May 15, 2015
    Copy the full SHA
    a1e06a2 View commit details
Original file line number Diff line number Diff line change
@@ -3,15 +3,17 @@
import org.jruby.RubyModule;
import org.jruby.ir.IRScope;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.runtime.ThreadContext;

/**
* Blocks and methods both share same full build mechanism so they implement this to be buildable.
*/
public interface FullBuildSource {
public interface Compilable<T> {
public void setCallCount(int count);
public void switchToFullBuild(InterpreterContext interpreterContext);
public void completeBuild(T buildResult);
public IRScope getIRScope();
public InterpreterContext ensureInstrsReady();
public String getClassName(ThreadContext context);
public String getName();
public String getFile();
public int getLine();
93 changes: 34 additions & 59 deletions core/src/main/java/org/jruby/compiler/JITCompiler.java
Original file line number Diff line number Diff line change
@@ -137,49 +137,30 @@ public long getLargestCodeSize() {
}

public void tearDown() {
if (executor != null) {
try {
executor.shutdown();
} catch (SecurityException se) {
// ignore, can't shut down executor
}
try {
executor.shutdown();
} catch (SecurityException se) {
// ignore, can't shut down executor
}
}

public void fullBuildThresholdReached(final FullBuildSource method, final RubyInstanceConfig config) {
// Disable any other jit tasks from entering queue
method.setCallCount(-1);

Runnable jitTask = new FullBuildTask(method);

if (config.getJitThreshold() > 0) {
if (config.getJitBackground() && executor != null) {
try {
executor.submit(jitTask);
} catch (RejectedExecutionException ree) {
// failed to submit, just run it directly
jitTask.run();
}
} else {
// Because are non-asynchonously build if the JIT threshold happens to be 0 we will have no ic yet.
method.ensureInstrsReady();
// just run directly
jitTask.run();
}
public Runnable getTaskFor(ThreadContext context, Compilable method) {
if (method instanceof MixedModeIRMethod) {
return new JITTask((MixedModeIRMethod) method, method.getClassName(context));
}

return new FullBuildTask(method);
}

public void jitThresholdReached(final MixedModeIRMethod method, final RubyInstanceConfig config, ThreadContext context, final String className, final String methodName) {

public void buildThresholdReached(ThreadContext context, final Compilable method) {
final RubyInstanceConfig config = context.runtime.getInstanceConfig();

// Disable any other jit tasks from entering queue
method.setCallCount(-1);

Runnable jitTask = new JITTask(className, method, methodName);

// if background JIT is enabled and threshold is > 0 and we have an executor...
if (config.getJitBackground() &&
config.getJitThreshold() > 0 &&
executor != null) {
// JIT in background
Runnable jitTask = getTaskFor(context, method);

if (config.getJitBackground() && config.getJitThreshold() > 0) {
try {
executor.submit(jitTask);
} catch (RejectedExecutionException ree) {
@@ -189,7 +170,6 @@ public void jitThresholdReached(final MixedModeIRMethod method, final RubyInstan
} else {
// Because are non-asynchonously build if the JIT threshold happens to be 0 we will have no ic yet.
method.ensureInstrsReady();

// just run directly
jitTask.run();
}
@@ -198,15 +178,15 @@ public void jitThresholdReached(final MixedModeIRMethod method, final RubyInstan
private static final MethodHandles.Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup().in(Ruby.class);

private class FullBuildTask implements Runnable {
private final FullBuildSource method;
private final Compilable method;

public FullBuildTask(FullBuildSource method) {
public FullBuildTask(Compilable method) {
this.method = method;
}

public void run() {
try {
method.switchToFullBuild(method.getIRScope().prepareFullBuild());
method.completeBuild(method.getIRScope().prepareFullBuild());

if (config.isJitLogging()) {
log(method.getImplementationClass(), method.getFile(), method.getLine(), method.getName(), "done building");
@@ -228,10 +208,10 @@ private class JITTask implements Runnable {
private final MixedModeIRMethod method;
private final String methodName;

public JITTask(String className, MixedModeIRMethod method, String methodName) {
this.className = className;
public JITTask(MixedModeIRMethod method, String className) {
this.method = method;
this.methodName = methodName;
this.className = className;
this.methodName = method.getName();
}

public void run() {
@@ -258,7 +238,7 @@ public void run() {
}
}

String key = SexpMaker.sha1(method.getIRMethod());
String key = SexpMaker.sha1(method.getIRScope());
JVMVisitor visitor = new JVMVisitor();
JITClassGenerator generator = new JITClassGenerator(className, methodName, key, runtime, method, visitor);

@@ -269,7 +249,7 @@ public void run() {
// that's so big that JVMs won't even try to compile it. Removed the check because with the new IR JIT
// bytecode counts often include all nested scopes, even if they'd be different methods. We need a new
// mechanism of getting all method sizes.
Class sourceClass = visitor.defineFromBytecode(method.getIRMethod(), generator.bytecode(), new OneShotClassLoader(runtime.getJRubyClassLoader()));
Class sourceClass = visitor.defineFromBytecode(method.getIRScope(), generator.bytecode(), new OneShotClassLoader(runtime.getJRubyClassLoader()));

if (sourceClass == null) {
// class could not be found nor generated; give up on JIT and bail out
@@ -293,47 +273,44 @@ public void run() {
log(method.getImplementationClass(), method.getFile(), method.getLine(), className + "." + methodName, "done jitting");
}

Map<Integer, MethodType> signatures = ((IRMethod)method.getIRMethod()).getNativeSignatures();
String jittedName = ((IRMethod)method.getIRMethod()).getJittedName();
Map<Integer, MethodType> signatures = ((IRMethod)method.getIRScope()).getNativeSignatures();
String jittedName = ((IRMethod)method.getIRScope()).getJittedName();
if (signatures.size() == 1) {
// only variable-arity
method.switchToJitted(
method.completeBuild(
new CompiledIRMethod(
PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, signatures.get(-1)),
method.getIRMethod(),
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRMethod().receivesKeywordArgs()));
method.getIRScope().receivesKeywordArgs()));

} else {
// also specific-arity
for (Map.Entry<Integer, MethodType> entry : signatures.entrySet()) {
if (entry.getKey() == -1) continue; // variable arity handle pushed above

method.switchToJitted(
method.completeBuild(
new CompiledIRMethod(
PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, signatures.get(-1)),
PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, entry.getValue()),
entry.getKey(),
method.getIRMethod(),
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRMethod().receivesKeywordArgs()));
method.getIRScope().receivesKeywordArgs()));
break;
}
}

return;
} catch (Throwable t) {
if (config.isJitLogging()) {
log(method.getImplementationClass(), method.getFile(), method.getLine(), className + "." + methodName, "Could not compile; passes run: " + method.getIRMethod().getExecutedPasses(), t.getMessage());
log(method.getImplementationClass(), method.getFile(), method.getLine(), className + "." + methodName, "Could not compile; passes run: " + method.getIRScope().getExecutedPasses(), t.getMessage());
if (config.isJitLoggingVerbose()) {
t.printStackTrace();
}
}

counts.failCount.incrementAndGet();
return;
}
}
}
@@ -375,7 +352,6 @@ public JITClassGenerator(String className, String methodName, String key, Ruby r
this.className = packageName + "/" + className.replace('.', '/') + CLASS_METHOD_DELIMITER + JavaNameMangler.mangleMethodName(methodName) + "_" + digestString;
this.name = this.className.replaceAll("/", ".");
this.methodName = methodName;
this.ruby = ruby;
this.method = method;
this.visitor = visitor;
}
@@ -391,7 +367,7 @@ protected void compile() {

// This may not be ok since we'll end up running passes specific to JIT
// CON FIXME: Really should clone scope before passes in any case
bytecode = visitor.compileToBytecode(method.getIRMethod());
bytecode = visitor.compileToBytecode(method.getIRScope());

compileTime = System.nanoTime() - start;
}
@@ -426,7 +402,6 @@ public String toString() {
return methodName + "() at " + method.getFile() + ":" + method.getLine();
}

private final Ruby ruby;
private final String packageName;
private final String className;
private final String methodName;
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.compiler.FullBuildSource;
import org.jruby.compiler.Compilable;
import org.jruby.ir.IRMethod;
import org.jruby.ir.IRScope;
import org.jruby.ir.interpreter.InterpreterContext;
@@ -24,7 +24,7 @@
/**
* Method for -X-C (interpreted only execution). See MixedModeIRMethod for inter/JIT method impl.
*/
public class InterpretedIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware, FullBuildSource {
public class InterpretedIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware, Compilable<InterpreterContext> {
private static final Logger LOG = LoggerFactory.getLogger("InterpretedIRMethod");

private Signature signature;
@@ -58,7 +58,7 @@ public StaticScope getStaticScope() {

public ArgumentDescriptor[] getArgumentDescriptors() {
ensureInstrsReady(); // Make sure method is minimally built before returning this info
return ((IRMethod) method).getArgumentDescriptors();
return method.getArgumentDescriptors();
}

public Signature getSignature() {
@@ -256,7 +256,7 @@ protected void doDebug() {
}
}

public void switchToFullBuild(InterpreterContext interpreterContext) {
public void completeBuild(InterpreterContext interpreterContext) {
this.interpreterContext = interpreterContext;
}

@@ -265,19 +265,20 @@ public void switchToFullBuild(InterpreterContext interpreterContext) {
protected void promoteToFullBuild(ThreadContext context) {
Ruby runtime = context.runtime;

// don't Promote to full build during runtime boot
if (runtime.isBooting()) return;
if (runtime.isBooting()) return; // don't Promote to full build during runtime boot

if (callCount++ >= Options.JIT_THRESHOLD.load()) {
runtime.getJITCompiler().fullBuildThresholdReached(this, context.runtime.getInstanceConfig());
}
if (callCount++ >= Options.JIT_THRESHOLD.load()) runtime.getJITCompiler().buildThresholdReached(context, this);
}

@Override
public DynamicMethod dup() {
return new InterpretedIRMethod(method, visibility, implementationClass);
}

public String getClassName(ThreadContext context) {
return null;
}

public String getFile() {
return method.getFileName();
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.jruby.internal.runtime.methods;

import org.jruby.MetaClass;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.compiler.Compilable;
import org.jruby.ir.*;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.runtime.IRRuntimeHelpers;
@@ -21,7 +21,7 @@
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

public class MixedModeIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware {
public class MixedModeIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware, Compilable<DynamicMethod> {
private static final Logger LOG = LoggerFactory.getLogger("InterpretedIRMethod");

private Signature signature;
@@ -49,18 +49,14 @@ public MixedModeIRMethod(IRScope method, Visibility visibility, RubyModule imple
}
}

public IRScope getIRMethod() {
public IRScope getIRScope() {
return method;
}

public DynamicMethod getActualMethod() {
return box.actualMethod;
}

public void setCallCount(int callCount) {
box.callCount = callCount;
}

public StaticScope getStaticScope() {
return method.getStaticScope();
}
@@ -303,20 +299,21 @@ public DynamicMethod getMethodForCaching() {
return this;
}

public void switchToJitted(CompiledIRMethod newMethod) {
@Override
public void completeBuild(DynamicMethod 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;
if (context.runtime.isBooting()) return; // don't JIT during runtime boot

// don't JIT during runtime boot
if (runtime.isBooting()) return;
if (box.callCount++ >= Options.JIT_THRESHOLD.load()) context.runtime.getJITCompiler().buildThresholdReached(context, this);
}

public String getClassName(ThreadContext context) {
String className;
if (implementationClass.isSingleton()) {
MetaClass metaClass = (MetaClass)implementationClass;
@@ -333,11 +330,7 @@ protected void tryJit(ThreadContext context, DynamicMethodBox box) {
// 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);
}
return className;
}

public void setActualMethod(CompiledIRMethod method) {
@@ -363,4 +356,8 @@ public String getFile() {
public int getLine() {
return method.getLineNumber();
}

public void setCallCount(int callCount) {
box.callCount = callCount;
}
}
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/IRScope.java
Original file line number Diff line number Diff line change
@@ -569,6 +569,7 @@ public synchronized FullInterpreterContext prepareFullBuild() {
if (!isUnsafeScope()) new AddCallProtocolInstructions().run(this);

fullInterpreterContext.generateInstructionsForIntepretation();
System.out.println("FOC : " + fullInterpreterContext.toStringInstrs());
return fullInterpreterContext;
}

2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/interpreter/Profiler.java
Original file line number Diff line number Diff line change
@@ -160,7 +160,7 @@ public int compare(IRCallSite a, IRCallSite b) {
IRScope hc = isHotClosure ? hs : null;
hs = isHotClosure ? hs.getLexicalParent() : hs;

IRScope tgtMethod = ircs.tgtM.getIRMethod();
IRScope tgtMethod = ircs.tgtM.getIRScope();

Instr[] instrs = tgtMethod.getInterpreterContext().getInstructions();
// Dont inline large methods -- 500 is arbitrary
Loading