Application failure after updating to Java 7u40 with invokedynamic #1005
On one of our airport applications we tried updating to Java 7u40, and all hell broke loose. The most noticeable symptom is that columns added by ActiveRecord migrations are not recognised later in the app.
This has been tested with JRuby 1.7.4 and 1.7.5.dev (2013-09-11), on Linux, Windows, and OS X.
Turning off InvokeDynamic restores normal behaviour.
I thought I'd ask if there are known issues with InvokeDynamic and/or Java 7u40 before spending time on reproduction.
Are there any known issues with JRuby and InvokeDynamic and/or Java 7u40?
The text was updated successfully, but these errors were encountered:
Maybe related to this bug.
Using 1.7.4. After updating to 7u40 today I got unstable problem during reloading model:
Ok, I finally have an explanation for this one.
Here's a reproduction that I'll use to discuss the problem: https://gist.github.com/headius/6599215
So the issue here is how the @@ variables are accessed.
@@var class vars are loaded using the current static scope (lexical scope from parser) which contains a reference to the surrounding class at the time the code was instantiated. The scope itself gets stored either in the AST (interpreter) or in the AbstractScript associated with the compiled code. When retrieving an class variable, we first acquire a reference to the scope and then look up the variable against the class it references.
In the non-indy compiler, the scope is retrieved each time from the AbstractScript object associated with the currently executing code. This requires hopping through a couple levels of indirection, but if the same JVM bytecode is used with different logical code bodies, they continue to work properly since they always go to the AbstractScript object.
The situation with indy is a bit different.
In order to make it possible for the JVM JIT to fold away repeated accesses of the same scope, we permanently cache the scope at the physical call site. The call site is unique to a given loaded piece of bytecode, so if the same loaded bytecode gets shared across logically different code bodies, we can end up using the scope associated with a previously jitted version of the same code. That's what's happening here.
In my example, the class variable accessors for @@bar are eval'ed into multiple classes, but to our JIT cache they look identical since they don't include anything to make them appear unique for each class. This means we use a single loaded version of the bytecode and all subclasses end up sharing the same bytecode. This means, in turn, they share a single call site...and the hard caching of the scope ends up going to the first method to JIT. In this case, that means FooAlpha's bar and @@bar are used rather than FooBeta's when the latter's bar methods JIT.
The core problem here is the caching for JVM bytecode/class for a JITed method does not have a sufficiently unique key to represent identical bytecode that has different runtime artifacts attached to it...like static scope.
There are a few ways to fix this:
I'm leaning strongly enough toward the third option that I'm going to go with it for now. So many of our uses of invokedynamic require the loaded code and call sites to be as unique as the logical methods they represent, and I can think of several other places where the current caching could (and maybe already is) biting us. This will potentially mean JRuby apps running under indy load more code, but in actuality it will almost exclusively affect multi-instance applications. Provide the JVM with more memory or run a single instance.
Thank you! It works perfectly in the test case and in our app. Excellent!
One observation though:
The given test case with AircraftType and BlacklistedCard loading from a YAML file takes around 40 seconds with indy disabled and over 80 seconds with indy enabled, all other settings equal.
I assume this is not the intended effect of activating indy :) Is this a known issue or should I file it?
@BanzaiMan But JRuby 1.7.5 has 200 resolved issues, any of which could have introduced a regression issue or an incompatibility with existing code. This is not to undermine the quality of development, but these issues can happen. The development community needs time to assert the status of 1.7.5 as being stable. So I was hoping to make something like 126.96.36.199 that would include just this fix, without forcing us to go with a new release whose stability is not yet guaranteed..