Skip to content

Global eventually ignores assignment #1375

Closed
JasonLunn opened this Issue Dec 31, 2013 · 7 comments

3 participants

@JasonLunn

OS X 10.7.5
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

jruby 1.7.3 (1.9.3p385) 2013-02-21 dac429b on Java HotSpot(TM) 64-Bit Server VM 1.7.0_45-b18 +indy [darwin-x86_64]
[via rvm 1.24.7 (stable)]

I am observing a consistent failure of assignment to a global in a unit test that defies debugging, because running the code with the debugger (even without break points set) makes the problem vanish.

I've resorted to console output debugging that you can see a snapshot of below. The key things to know:

  • Multi-threading issues shouldn't be at play here, since the unit test is not explicitly multithreaded
  • Even if multithreading were an issue, the code in question is executed within a synchronized block, $vm_lock is an instance of java.lang.Object, and no other code in the code base accesses $cache_load_number for reading or writing outside of a block synchronized on $vm_lock
  • The test consistently fails incrementing $cache_load_number from 100 to 101, every time.
  • I have tried both $cache_load_number += 1 and $cache_load_number = $cache_load_number + 1 and the results are identical

The output observed, shown in the console log should be impossible:

Cache Load Number: 100 before increment (Fixnum)
Cache Load Number: 100 end of synchronized block (Fixnum)

screen shot 2013-12-31 at 12 32 37 pm

@JasonLunn

I think that I've isolated the minimum failure case:

jruby -e '$counter = 0; 200.times{ local_counter = $counter; $counter += 1; raise "Counter == #{local_counter}" if local_counter == $counter };'

Produces:

RuntimeError: Counter == 100
  (root) at -e:1
   times at org/jruby/RubyFixnum.java:273
  (root) at -e:1
@JasonLunn

A colleague was able to verify my findings on an Ubuntu system, but also adds that the JDK version is critical to reproducing the issue. For him, the error reproduced on the build 45 JDK but was not reproducible on an older build 25 JDK:

java version "1.7.0_25"
OpenJDK Runtime Environment (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)
@headius
JRuby Team member
headius commented Dec 31, 2013

Ok, I know the problem here, and the JDK version and JRuby version are key to the issue. It's a problem with how we do caching of global variables when using invokedynamic. The 100 update cutoff is exactly where the indy logic stops trying to cache the value; however it appears that instead of bailing out on caching, it bails out on updating. Shouldn't be a difficult fix.

@headius headius closed this in 0a1a6f3 Jan 1, 2014
@headius
JRuby Team member
headius commented Jan 1, 2014

Fixed but reopening because I want to add a test.

@headius headius reopened this Jan 1, 2014
@headius
JRuby Team member
headius commented Jan 1, 2014

Workaround for you is to update to a newer JRuby (which will not use invokedynamic on 1.7.0_45), or to turn invokedynamic off with -Xcompile.invokedynamic=false. JRuby 1.7.10 will work in all scenarios, though.

@JasonLunn

Thanks for the quick response @headius, and Happy New Year!

@headius
JRuby Team member
headius commented Jan 2, 2014

Happy New Year to you as well!

@headius headius added a commit that referenced this issue Jan 2, 2014
@headius headius Regression spec for #1375. 820b312
@headius headius added a commit that referenced this issue Jan 2, 2014
@headius headius Regression spec for #1375. 3b8b790
@headius headius closed this Jan 2, 2014
@enebo enebo modified the milestone: JRuby 1.7.10, JRuby 1.7.11 Feb 24, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.