RFR: 8293336: AOT-linking of invokedynamic for lambda expression and string concat

John Rose john.r.rose at oracle.com
Wed Oct 9 06:40:19 UTC 2024


On 8 Oct 2024, at 14:47, Ioi Lam wrote:

> On Wed, 25 Sep 2024 17:14:54 GMT, Chen Liang <liach at openjdk.org> wrote:
>
>>> 402:         MethodType primordialMT = new MethodType(rtype, ptypes);
>>> 403:         if (AOTHolder.archivedMethodTypes != null) {
>>> 404:             MethodType mt = AOTHolder.archivedMethodTypes.get(primordialMT);
>>
>> Can we populate these AOT MTs into the internTable so we only look up once?
>
> There's a trade off here --
> start-up will be slowed down if the archivedMethodTypes table is big. Also, `internTable` uses more memory as it wraps every entry inside a weak reference.

I think there is a design pattern should be thinking about,
which I have been calling the “Three Table Solution”.  (And
there might be just Two Tables.)  The runtime table is the
existing intern table with its weak references.  It is
designed for fast queries, fast updates, and good relations
with the GC.  It does not have the best possible footprint.
The AOT table is archivedMethodTypes.  It is designed for
compactness, fast static boot-up, and reasonably fast queries.
It is read-only.  (It is permitted to have slower queries,
such as in a log N tree instead of O(1) hash table, but if
that is the case then entries should be migrated into the
main runtime table as they are extracted.)

A third table, maybe, is the startup table; it collects
entries at startup before the big main runtime table can
be created.  It might also serve instead of the runtime
table during the assembly phase.  Its main property is
simplicity, meaning lack of complex init-dependencies
on the rest of the JDK.  It does not need weak refs,
or any other kind of scalability, because it will
be quickly retired when the system boots up.  In
fact, the AOT table is likely to fulfill all early
queries, so the startup table is probably empty,
as long as an AOT cache is available.  The startup
table might be useful for exploded builds, as well
as for the assembly phase.  Note that while the
startup table exists, the main runtime table is
not yet created; its static reference is null.
(It should be a @Stable field!)

That third table is not very useful if we can figure
out how to use the main runtime table (with its
weak refs) at all init phases.  So maybe this design
pattern is the Two Table Solution, if we can tame
weak refs for Leyden.

But I do think we have a long-term need for two
tables, with an AOT one optimized for fast boot-up
and compactness (and slow to create, and not mutated
during startup).

The order of operations could be:

A. check AOT table; if present, return
B. check main table or startup table; if present, return
C. make new object, install in appropriate table, return

But in some cases it is better to always check the main
table first, if it exists.  (A @Stable reference will
make the query method inline, after the JIT gets ahold
of the object.)  Like this:

A. check main table; if present, return
B. check AOT table or startup table
B1. if present, and if main table exists, move to main table
B2. if present, then return
C. make new object, install in appropriate table, return

> PR Review Comment: https://git.openjdk.org/jdk/pull/21143#discussion_r1782292378


More information about the hotspot-dev mailing list