Skip to content

Multiple fixes for forced JIT and indy-based Java dispatch#7913

Merged
headius merged 8 commits intojruby:masterfrom
headius:indy_ji_arity_mismatch
Aug 30, 2023
Merged

Multiple fixes for forced JIT and indy-based Java dispatch#7913
headius merged 8 commits intojruby:masterfrom
headius:indy_ji_arity_mismatch

Conversation

@headius
Copy link
Member

@headius headius commented Aug 29, 2023

Several fixes here:

  • Arguments passed to either instance or static method must match arity of target Java method. Not sure how the -1 got in here but it may have been thinking in terms of a MethodType, which will have the self object as the first argument for instance methods.
  • This got past testing because of insufficient jitted code being tested with indy, so I enabled forced JIT and indy for more test suites and discovered additional issues.
  • Cleaned up caching of the Ruby to Java indy handle so that it would not be reused for incompatible shapes of call sites.
  • Removed caching of call site-specific adaptations on the handle. They must be reapplied for each form of call site that happens across the cached handle.
  • Commented out a test that I don't believe should ever have passed, but definitely does not pass when JIT-compiled. (JIT mode allows nulled out IRubyObject array to propagate null #7914)
  • Fixed constant definition from JIT to pass appropriate filename and line number.

We could use a better system for doing these adaptations and caching them appropriately for the different call site shapes, but this should work reasonably well for now. If a call site is stable, we should not have to re-adapt the method handle too frequently (or ever again after the first time), and the heavier adaptations that apply to all call sites will be reused.

Fixes #7904

Arguments passed to either instance or static method must match
arity of target Java method. Not sure how the -1 got in here but
it may have been thinking in terms of a MethodType, which will
have the self object as the first argument for instance methods.

Also not sure how this got past testing. More indy testing of JI
calls must be done.

Fixes jruby#7904
@headius headius added this to the JRuby 9.4.4.0 milestone Aug 29, 2023
This moves the indy-enabled Java 8 spec:ji run to the "latest LTS"
group (currently 21-ea) and adds additional flags there to force
compilation.

The latter change is needed in order for some types of tests to
fully compile (like rspec specs, which usually have only blocks
down to the root of the script). Both flags are required to force
compilation of whole files (e.g. specs) or individual methods and
blocks (if whole file fails or new methods are evaluated at
runtime). This should help catch more indy issues.
The logic here would perform several checks to see if the Java
method were bindable to the given call site. If all checks passed,
a handle would be constructed and saved into the Java invoker.
However, those same checks were not performed for future calls at
different call sites, causing those sites to mismatch arity if
they differed from the originating site.

The fix here does two things to prevent the cached handle from
being used when it doesn't match:

* Finish all return value conversions so there are fewer
unbindable cases and non after acquiring the direct handle.
* Move the remaining checks above the use of the cached handle, so
we can be assured that a handle would be bound to this site with
or without the cache.

Because there's only ever one NativeCall form and one cache entry,
we know it will be the same signature and arity at this point, and
can safely use the cached handle.

In the future, when we improve this logic to support multiple
overloads for a target Java method, combined with multiple
incoming arities (and the other bail-out cases) this logic will
need to cache handles on a per-shape basis (or accept not caching
more than one shape).
In jruby#7589 I reduced the call site size for functional
calls ("self" calls) by omitting the caller argument normally
used to check visibility. This change was never applied to the
Java invokedynamic binding logic, resulting in arity mismatches
when a Java method is called from within an instance of itself or
when calling a Java method through an alias, since the alias
is rebound as a self call.

This change specializes the number of arguments to drop from the
beginning of the argument list based additionally upon whether it
is a functional call site:

* static and functional: drop 2 (context and self)
* static and normal: drop 3 (context and caller and self)
* instance and functional: drop 1 (context)
* instance and normal: drop 2 (context and caller)
Caching the entire handle embeds call site-specific adaptations
into it, making it unsuitable for other shapes of call site (e.g
functional site without caller versus normal site with caller) and
with no way to detect that situation.

Instead, this change caches only the adaptations made to the
original direct method handle, which will be the same for all
consumers.
@headius headius changed the title Signature arity should match in both cases Multiple fixes for Ruby to Java indy-based method calling Aug 30, 2023
@headius headius changed the title Multiple fixes for Ruby to Java indy-based method calling Multiple fixes for forced JIT and indy-based Java dispatch Aug 30, 2023
JIT-compiled methods do not populate ThreadContext file and line,
so those will reflect whatever the last interpreted frame was.
@headius headius force-pushed the indy_ji_arity_mismatch branch from 0046bd5 to 4a7b6b5 Compare August 30, 2023 04:51
@headius headius marked this pull request as ready for review August 30, 2023 06:05
@headius headius merged commit 6615c0e into jruby:master Aug 30, 2023
@headius headius deleted the indy_ji_arity_mismatch branch August 30, 2023 06:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

invokedynamic makes Concurrent::TimerTask.execute reliably result in java.lang.invoke.WrongMethodTypeException

1 participant