Skip to content

Commit

Permalink
Showing 116 changed files with 2,453 additions and 851 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -73,6 +73,8 @@ tool/nailgun/config.log
tool/nailgun/config.status
tool/nailgun/ng
reference.txt
rubyspec_temp
.polyglot.pom.rb

# binaries
!bin/gem
@@ -109,4 +111,4 @@ findbugs-noUpdateChecks-3.0.0.tar.gz
findbugs-3.0.0

# Vagrant
/.vagrant
.vagrant
8 changes: 5 additions & 3 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -930,16 +930,18 @@ private TruffleContextInterface loadTruffleContext() {
throw new RuntimeException("Truffle backend not available", e);
}

final TruffleContextInterface truffleBridge;
final TruffleContextInterface truffleContext;

try {
Constructor<?> con = clazz.getConstructor(Ruby.class);
truffleBridge = (TruffleContextInterface) con.newInstance(this);
truffleContext = (TruffleContextInterface) con.newInstance(this);
} catch (Exception e) {
throw new RuntimeException("Error while calling the constructor of Truffle's RubyContext", e);
}

return truffleBridge;
truffleContext.initialize();

return truffleContext;
}

public void shutdownTruffleContextIfRunning() {
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/TruffleContextInterface.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,8 @@ enum BacktraceFormatter {
IMPL_DEBUG
}

void initialize();

Object execute(org.jruby.ast.RootNode rootNode);

void shutdown();
9 changes: 3 additions & 6 deletions core/src/main/java/org/jruby/ast/Node.java
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
package org.jruby.ast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.jruby.ParseResult;
@@ -79,11 +80,7 @@ public void setPosition(ISourcePosition position) {
public abstract List<Node> childNodes();

protected static List<Node> createList(Node node) {
ArrayList<Node> list = new ArrayList<>(1);

list.add(node);

return list;
return Collections.singletonList(node);
}

protected static List<Node> createList(Node node1, Node node2) {
@@ -218,4 +215,4 @@ public boolean needsDefinitionCheck() {
public boolean containsVariableAssignment() {
return containsVariableAssignment;
}
}
}
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();
}
Loading

0 comments on commit 4bd8d71

Please sign in to comment.