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: 7d91bdd65818^
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9fbb25e3ad83
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Aug 18, 2017

  1. Synchronize bytecode JIT to avoid concurrency issues.

    This effectively means the background JIT will usually be limited
    to one thread operating at a time. How much this will slow down
    or bottleneck the JIT is not clear but this fix will let us know
    if we need a deeper look at synchronization of the JIT and IR
    structures modified at JIT time.
    
    Part of work for #4739.
    headius committed Aug 18, 2017
    Copy the full SHA
    7d91bdd View commit details
  2. Copy the full SHA
    c203a88 View commit details
  3. Copy the full SHA
    9fbb25e View commit details
76 changes: 39 additions & 37 deletions core/src/main/java/org/jruby/compiler/BlockJITTask.java
Original file line number Diff line number Diff line change
@@ -47,52 +47,54 @@ public BlockJITTask(JITCompiler jitCompiler, MixedModeIRBlockBody body, String c
}

public void run() {
try {
String key = SexpMaker.sha1(body.getIRScope());
JVMVisitor visitor = new JVMVisitor();
BlockJITClassGenerator generator = new BlockJITClassGenerator(className, methodName, key, jitCompiler.runtime, body, visitor);
synchronized (jitCompiler) {
try {
String key = SexpMaker.sha1(body.getIRScope());
JVMVisitor visitor = new JVMVisitor();
BlockJITClassGenerator generator = new BlockJITClassGenerator(className, methodName, key, jitCompiler.runtime, body, visitor);

JVMVisitorMethodContext context = new JVMVisitorMethodContext();
generator.compile(context);
JVMVisitorMethodContext context = new JVMVisitorMethodContext();
generator.compile(context);

// FIXME: reinstate active bytecode size check
// At this point we still need to reinstate the bytecode size check, to ensure we're not loading code
// 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 body sizes.
Class sourceClass = visitor.defineFromBytecode(body.getIRScope(), generator.bytecode(), new OneShotClassLoader(jitCompiler.runtime.getJRubyClassLoader()));
// FIXME: reinstate active bytecode size check
// At this point we still need to reinstate the bytecode size check, to ensure we're not loading code
// 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 body sizes.
Class sourceClass = visitor.defineFromBytecode(body.getIRScope(), generator.bytecode(), new OneShotClassLoader(jitCompiler.runtime.getJRubyClassLoader()));

if (sourceClass == null) {
// class could not be found nor generated; give up on JIT and bail out
jitCompiler.counts.failCount.incrementAndGet();
return;
} else {
generator.updateCounters(jitCompiler.counts, body.ensureInstrsReady());
}
if (sourceClass == null) {
// class could not be found nor generated; give up on JIT and bail out
jitCompiler.counts.failCount.incrementAndGet();
return;
} else {
generator.updateCounters(jitCompiler.counts, body.ensureInstrsReady());
}

// successfully got back a jitted body
// successfully got back a jitted body

if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(body.getImplementationClass(), body.getFile(), body.getLine(), className + "." + methodName, "done jitting");
}
String jittedName = context.getVariableName();

String jittedName = context.getVariableName();
// blocks only have variable-arity
body.completeBuild(
new CompiledIRBlockBody(
JITCompiler.PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, JVMVisitor.CLOSURE_SIGNATURE.type()),
body.getIRScope(),
((IRClosure) body.getIRScope()).getSignature().encode()));

// blocks only have variable-arity
body.completeBuild(
new CompiledIRBlockBody(
JITCompiler.PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, JVMVisitor.CLOSURE_SIGNATURE.type()),
body.getIRScope(),
((IRClosure) body.getIRScope()).getSignature().encode()));
} catch (Throwable t) {
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(body.getImplementationClass(), body.getFile(), body.getLine(), className + "." + methodName, "Could not compile; passes run: " + body.getIRScope().getExecutedPasses(), t.getMessage());
if (jitCompiler.config.isJitLoggingVerbose()) {
t.printStackTrace();
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(body.getImplementationClass(), body.getFile(), body.getLine(), className + "." + methodName, "done jitting");
}
} catch (Throwable t) {
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(body.getImplementationClass(), body.getFile(), body.getLine(), className + "." + methodName, "Could not compile; passes run: " + body.getIRScope().getExecutedPasses(), t.getMessage());
if (jitCompiler.config.isJitLoggingVerbose()) {
t.printStackTrace();
}
}
}

jitCompiler.counts.failCount.incrementAndGet();
jitCompiler.counts.failCount.incrementAndGet();
}
}
}
}
148 changes: 75 additions & 73 deletions core/src/main/java/org/jruby/compiler/MethodJITTask.java
Original file line number Diff line number Diff line change
@@ -53,103 +53,105 @@ public MethodJITTask(JITCompiler jitCompiler, MixedModeIRMethod method, String c
}

public void run() {
try {
// Check if the method has been explicitly excluded
if (jitCompiler.config.getExcludedMethods().size() > 0) {
String excludeModuleName = className;
if (method.getImplementationClass().getMethodLocation().isSingleton()) {
IRubyObject possibleRealClass = ((MetaClass) method.getImplementationClass()).getAttached();
if (possibleRealClass instanceof RubyModule) {
excludeModuleName = "Meta:" + ((RubyModule) possibleRealClass).getName();
synchronized (jitCompiler) {
try {
// Check if the method has been explicitly excluded
if (jitCompiler.config.getExcludedMethods().size() > 0) {
String excludeModuleName = className;
if (method.getImplementationClass().getMethodLocation().isSingleton()) {
IRubyObject possibleRealClass = ((MetaClass) method.getImplementationClass()).getAttached();
if (possibleRealClass instanceof RubyModule) {
excludeModuleName = "Meta:" + ((RubyModule) possibleRealClass).getName();
}
}
}

if ((jitCompiler.config.getExcludedMethods().contains(excludeModuleName)
|| jitCompiler.config.getExcludedMethods().contains(excludeModuleName + '#' + methodName)
|| jitCompiler.config.getExcludedMethods().contains(methodName))) {
method.setCallCount(-1);
if ((jitCompiler.config.getExcludedMethods().contains(excludeModuleName)
|| jitCompiler.config.getExcludedMethods().contains(excludeModuleName + '#' + methodName)
|| jitCompiler.config.getExcludedMethods().contains(methodName))) {
method.setCallCount(-1);

if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), methodName, "skipping method: " + excludeModuleName + '#' + methodName);
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), methodName, "skipping method: " + excludeModuleName + '#' + methodName);
}
return;
}
return;
}
}

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

JVMVisitorMethodContext context = new JVMVisitorMethodContext();
generator.compile(context);
JVMVisitorMethodContext context = new JVMVisitorMethodContext();
generator.compile(context);

// FIXME: reinstate active bytecode size check
// At this point we still need to reinstate the bytecode size check, to ensure we're not loading code
// 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.getIRScope(), generator.bytecode(), new OneShotClassLoader(jitCompiler.runtime.getJRubyClassLoader()));
// FIXME: reinstate active bytecode size check
// At this point we still need to reinstate the bytecode size check, to ensure we're not loading code
// 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.getIRScope(), generator.bytecode(), new OneShotClassLoader(jitCompiler.runtime.getJRubyClassLoader()));

if (sourceClass == null) {
// class could not be found nor generated; give up on JIT and bail out
jitCompiler.counts.failCount.incrementAndGet();
return;
} else {
generator.updateCounters(jitCompiler.counts, method.ensureInstrsReady());
}
if (sourceClass == null) {
// class could not be found nor generated; give up on JIT and bail out
jitCompiler.counts.failCount.incrementAndGet();
return;
} else {
generator.updateCounters(jitCompiler.counts, method.ensureInstrsReady());
}

// successfully got back a jitted method
long methodCount = jitCompiler.counts.successCount.incrementAndGet();
// successfully got back a jitted method
long methodCount = jitCompiler.counts.successCount.incrementAndGet();

// logEvery n methods based on configuration
if (jitCompiler.config.getJitLogEvery() > 0) {
if (methodCount % jitCompiler.config.getJitLogEvery() == 0) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), methodName, "live compiled methods: " + methodCount);
// logEvery n methods based on configuration
if (jitCompiler.config.getJitLogEvery() > 0) {
if (methodCount % jitCompiler.config.getJitLogEvery() == 0) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), methodName, "live compiled methods: " + methodCount);
}
}
}

if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), className + '.' + methodName, "done jitting");
}
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), className + '.' + methodName, "done jitting");
}

String variableName = context.getVariableName();
MethodHandle variable = JITCompiler.PUBLIC_LOOKUP.findStatic(sourceClass, variableName, context.getNativeSignature(-1));
IntHashMap<MethodType> signatures = context.getNativeSignaturesExceptVariable();

String variableName = context.getVariableName();
MethodHandle variable = JITCompiler.PUBLIC_LOOKUP.findStatic(sourceClass, variableName, context.getNativeSignature(-1));
IntHashMap<MethodType> signatures = context.getNativeSignaturesExceptVariable();

if (signatures.size() == 0) {
// only variable-arity
method.completeBuild(
new CompiledIRMethod(
variable,
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRScope().receivesKeywordArgs()));

} else {
// also specific-arity
for (IntHashMap.Entry<MethodType> entry : signatures.entrySet()) {
if (signatures.size() == 0) {
// only variable-arity
method.completeBuild(
new CompiledIRMethod(
variable,
JITCompiler.PUBLIC_LOOKUP.findStatic(sourceClass, context.getSpecificName(), entry.getValue()),
entry.getKey(),
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRScope().receivesKeywordArgs()));
break; // FIXME: only supports one arity

} else {
// also specific-arity
for (IntHashMap.Entry<MethodType> entry : signatures.entrySet()) {
method.completeBuild(
new CompiledIRMethod(
variable,
JITCompiler.PUBLIC_LOOKUP.findStatic(sourceClass, context.getSpecificName(), entry.getValue()),
entry.getKey(),
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRScope().receivesKeywordArgs()));
break; // FIXME: only supports one arity
}
}
}
} catch (Throwable t) {
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), className + '.' + methodName, "Could not compile; passes run: " + method.getIRScope().getExecutedPasses(), t.getMessage());
if (jitCompiler.config.isJitLoggingVerbose()) {
t.printStackTrace();
} catch (Throwable t) {
if (jitCompiler.config.isJitLogging()) {
JITCompiler.log(method.getImplementationClass(), method.getFile(), method.getLine(), className + '.' + methodName, "Could not compile; passes run: " + method.getIRScope().getExecutedPasses(), t.getMessage());
if (jitCompiler.config.isJitLoggingVerbose()) {
t.printStackTrace();
}
}
}

jitCompiler.counts.failCount.incrementAndGet();
jitCompiler.counts.failCount.incrementAndGet();
}
}
}
}
12 changes: 9 additions & 3 deletions core/src/main/java/org/jruby/parser/StaticScope.java
Original file line number Diff line number Diff line change
@@ -114,7 +114,7 @@ public class StaticScope implements Serializable {

private RubyModule overlayModule;

private MethodHandle constructor;
private volatile MethodHandle constructor;

public enum Type {
LOCAL, BLOCK, EVAL;
@@ -187,16 +187,22 @@ public DynamicScope construct(DynamicScope parent) {
}
}

private MethodHandle acquireConstructor() {
MethodHandle constructor;
private synchronized MethodHandle acquireConstructor() {
// check again
MethodHandle constructor = this.constructor;

if (constructor != null) return constructor;

int numberOfVariables = getNumberOfVariables();

if (numberOfVariables > MAX_SPECIALIZED_SIZE) {
constructor = ManyVarsDynamicScope.CONSTRUCTOR;
} else {
constructor = DynamicScopeGenerator.generate(numberOfVariables);
}

this.constructor = constructor;

return constructor;
}

Original file line number Diff line number Diff line change
@@ -178,6 +178,9 @@ protected void promoteToFullBuild(ThreadContext context) {
}

synchronized (this) {
// check call count again
if (callCount < 0) return;

if (callCount++ >= Options.JIT_THRESHOLD.load()) {
callCount = -1;
context.runtime.getJITCompiler().buildThresholdReached(context, this);