Tiered compilation leads to "unloaded signature class" inlining failures in JRuby

Claes Redestad claes.redestad at oracle.com
Mon Jun 15 21:23:24 UTC 2020


Hi,

I added a little debug logging[1] and ran your reproducer which indicate
several classes/methods have what the VM considers to be un-initialized
classes, and the method in particular doesn't seem to be finding 
java/lang/String:

[2.197s][debug][unload,resolve] has_unloaded_classes_in_signature: could 
not resolve klass java/lang/String in method 
path.to.my.script.dir.jruby_minus_9_dot_2_dot_11_dot_1.inline.RUBY$method$bar$0(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/parser/StaticScope;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;Lorg/jruby/RubyModule;Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;

This is obviously pretty weird, but looks eerily similar to
https://bugs.openjdk.java.net/browse/JDK-8000263

- root issue there was use of Unsafe.getObject in a way that hasn't
ensured proper initialization of fields in a way that sets up class
loader constraints.

If so, a possible workaround might be to pass the generated class
through Unsafe.ensureClassInitialized (or Lookup.ensureInitialized if on
15+)

/Claes

[1]

diff -r a3905846b9ae src/hotspot/share/oops/method.cpp
--- a/src/hotspot/share/oops/method.cpp	Mon Jun 15 15:56:16 2020 +0200
+++ b/src/hotspot/share/oops/method.cpp	Mon Jun 15 23:11:14 2020 +0200
@@ -1717,7 +1717,13 @@
        // unloaded array component types.
        Klass* klass = ss.as_klass_if_loaded(THREAD);
        assert(!HAS_PENDING_EXCEPTION, "as_klass_if_loaded contract");
-      if (klass == NULL) return true;
+      if (klass == NULL) {
+        ss.as_symbol()
+        log_debug(unload, resolve)("has_unloaded_classes_in_signature: 
could not resolve klass %s in method %s",
+                            ss.as_symbol()->as_C_string(),
+                            m()->name_and_sig_as_C_string());
+        return true;
+      }
      }
    }
    return false;

On 2020-06-14 16:04, Charles Oliver Nutter wrote:
> We received a bug report today showing that JRuby's bytecode-compiled
> methods do not appear to be inlining properly on Hotspot.
> 
> https://github.com/jruby/jruby/issues/6280
> 
> A bit of background here...
> 
> JRuby is itself a tiered runtime. Most Ruby methods will be
> interpreted in our IR form for a while until a call threshold is
> reached. At that point, we JIT the method into JVM bytecode and use
> that code from that point forward
> 
> We also optionally use invokedynamic for dynamic call sites (via the
> -Xcompile.invokedynamic JRuby flag), which makes it possible for most
> method calls to inline.
> 
> Because Ruby methods can be overwritten at runtime, or whole Ruby
> classes might be transient, most of these jitted methods are contained
> within their own unique JVM classes, and also within their own unique
> classloaders. This allows them to unload when no longer in use.
> 
> This should not affect inlining one of these methods into another, and
> historically it has worked fine.
> 
> The bug report above shows that a trivial method call fails to inline
> with "unloaded signature class" (according to PrintInlining), and my
> experiments seem to indicate this only happens when tiered compilation
> is enabled. DIsabling tiered compilation and using C2 alone inlines
> fine and we get the native code we expect.
> 
> The signatures of these methods are not exotic... the only classes
> specified are classes critical to the operation of JRuby itself, and
> they would have been loaded and in use long before these inlining
> decisions would be made. The jitted bytecode class itself is defined
> and subsequently passes through various reflection APIs, so it should
> also be fully loaded and resolved.
> 
> So we have a puzzle. Why does running this code with tiered
> compilation cause it to (erroneously?) claim a signature class has not
> been loaded?
> 
> This appears to affect every OpenJDK release at least back to 8u222,
> the earliest version we tested.
> 
> To reproduce, create the two scripts in the bug, download a JRuby
> distribution from jruby.org, and execute the main script like this:
> 
> bin/jruby -Xcompile.invokedynamic -J-XX:+WhateverHotspotFlag main.rb
> 
> PrintInlining and PrintAssembly output will show that the "bar" method
> fails to inline into "foo" in the inline.rb part of the example.
> 
> Help!
> 
> - Charlie
> 


More information about the hotspot-compiler-dev mailing list