-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
On JRuby 9.2.9.0, we can successfully run code that calls functions within a Thread from pre-compiled JRuby classes.
The exact same situation (pre-compiled JRuby classes, multi-threaded code that calls a function) crashes on JRuby 9.2.10.0 and JRuby 9.2.11.0 (haven't tested 9.2.11.1 or 9.3).
We are running JDK1.8, and have been able to reproduce this on MacOS, Ubuntu, and Alpine. We have also been able to reproduce with both the default JRUBY_OPTS, and also with compile.invokedynamic=true.
FWIW, the same code with NUM_THREADS = 1 succeeds when run from a pre-compiled JRuby class (fails for NUM_THREADS > 1)
Here are the steps to reproduce the bug:
- Using JRuby 9.2.10.0+, compile the following code using
jrubyc
# test.rb
NUM_THREADS = 16
SAMPLE_SIZE = 10_000
def sample
a = Array.new(SAMPLE_SIZE) { |i| rand }
a.inject(0.0, :+) / SAMPLE_SIZE.to_f
end
means = Array.new(NUM_THREADS) { 0 }
# Works, if not called within a Thread
# NUM_THREADS.times { |i| means[i] = sample }
threads = []
NUM_THREADS.times { |i|
threads << Thread.new {
# Crashes when `sample` is called with threads
means[i] = sample
# Works, if function body of `sample` is called in the thread directly
# a = Array.new(SAMPLE_SIZE) { |i| rand }
# means[i] = a.inject(0.0, :+) / SAMPLE_SIZE.to_f
}
}
threads.map(&:join)
puts means.inject(0.0, :+) / NUM_THREADS.to_f
- Run the compiled class:
jruby test.class
Expected Behavior
When compiled and run using JRuby 9.2.9.0, this test should return a number near 0.5.
Actual Behavior
When compiled and run using JRuby 9.2.10.0 and JRuby 9.2.11.0 (again, haven't tested beyond those), this same test crashes with the following stack trace:
warning: thread "Ruby-0-Thread-2: test.class:25" terminated with exception (report_on_exception is true):
warning: thread "Ruby-0-Thread-1: test.class:25" terminated with exception (report_on_exception is true):
java.lang.NullPointerException
at org.jruby.ir.persistence.IRReaderStream.decodeEncoding(IRReaderStream.java:94)
at org.jruby.ir.persistence.IRReaderStream.decodeSymbolFromConstantPool(IRReaderStream.java:126)
at org.jruby.ir.persistence.IRReaderStream.decodeConstantPool(IRReaderStream.java:201)
at org.jruby.ir.persistence.IRReaderStream.decodeInstructionsAt(IRReaderStream.java:208)
at org.jruby.ir.persistence.IRReader.lambda$load$0(IRReader.java:47)
at org.jruby.ir.interpreter.InterpreterContext.getEngine(InterpreterContext.java:74)
at org.jruby.ir.interpreter.InterpreterContext.hasExplicitCallProtocol(InterpreterContext.java:206)
at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:116)
at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:108)
at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:192)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:141)
at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:345)
at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:72)
at org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:116)
at org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:136)
at org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:60)
at org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:52)
at org.jruby.runtime.Block.call(Block.java:139)
at org.jruby.RubyProc.call(RubyProc.java:318)
at org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:105)
at java.lang.Thread.run(Thread.java:745)
java.lang.NullPointerException
at org.jruby.ir.persistence.IRReaderStream.decode(IRReaderStream.java:478)
at org.jruby.ir.persistence.IRReaderStream.decodeOperand(IRReaderStream.java:371)
at org.jruby.ir.persistence.IRReaderStream.decodeVariable(IRReaderStream.java:380)
at org.jruby.ir.instructions.LoadImplicitClosureInstr.decode(LoadImplicitClosureInstr.java:33)
at org.jruby.ir.persistence.IRReaderStream.decodeInstr(IRReaderStream.java:289)
at org.jruby.ir.persistence.IRReaderStream.decodeInstructionsAt(IRReaderStream.java:218)
at org.jruby.ir.persistence.IRReader.lambda$load$0(IRReader.java:47)
at org.jruby.ir.interpreter.InterpreterContext.getEngine(InterpreterContext.java:74)
at org.jruby.ir.interpreter.InterpreterContext.hasExplicitCallProtocol(InterpreterContext.java:206)
at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:116)
at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:108)
at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:192)
at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:354)
at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:143)
at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:345)
at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:72)
at org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:116)
at org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:136)
at org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:60)
at org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:52)
at org.jruby.runtime.Block.call(Block.java:139)
at org.jruby.RubyProc.call(RubyProc.java:318)
at org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:105)
at java.lang.Thread.run(Thread.java:745)
Unhandled Java exception: java.lang.NullPointerException
java.lang.NullPointerException: null
decode at org/jruby/ir/persistence/IRReaderStream.java:478
decodeOperand at org/jruby/ir/persistence/IRReaderStream.java:371
decodeVariable at org/jruby/ir/persistence/IRReaderStream.java:380
decode at org/jruby/ir/instructions/LoadImplicitClosureInstr.java:33
decodeInstr at org/jruby/ir/persistence/IRReaderStream.java:289
decodeInstructionsAt at org/jruby/ir/persistence/IRReaderStream.java:218
lambda$load$0 at org/jruby/ir/persistence/IRReader.java:47
getEngine at org/jruby/ir/interpreter/InterpreterContext.java:74
hasExplicitCallProtocol at org/jruby/ir/interpreter/InterpreterContext.java:206
INTERPRET_METHOD at org/jruby/internal/runtime/methods/MixedModeIRMethod.java:116
call at org/jruby/internal/runtime/methods/MixedModeIRMethod.java:108
call at org/jruby/internal/runtime/methods/DynamicMethod.java:192
cacheAndCall at org/jruby/runtime/callsite/CachingCallSite.java:354
call at org/jruby/runtime/callsite/CachingCallSite.java:143
processCall at org/jruby/ir/interpreter/InterpreterEngine.java:345
interpret at org/jruby/ir/interpreter/StartupInterpreterEngine.java:72
INTERPRET_BLOCK at org/jruby/ir/interpreter/Interpreter.java:116
commonYieldPath at org/jruby/runtime/MixedModeIRBlockBody.java:136
call at org/jruby/runtime/IRBlockBody.java:60
call at org/jruby/runtime/IRBlockBody.java:52
call at org/jruby/runtime/Block.java:139
call at org/jruby/RubyProc.java:318
run at org/jruby/internal/runtime/RubyRunnable.java:105
run at java/lang/Thread.java:745