Condy for LambdaMetafactory?
Luke Sandberg
lukes at google.com
Sun Oct 22 16:20:10 UTC 2023
In my case this happens to not be a concern for structural reasons... The
lambdas in question are used to satisfy one of the 3 available calling
conventions for functions in my languages (we can compile calls to 'static
positional calls', aka, invokestatic on a function like R foo(V v1,V v2,V
v3,...), 'static map calls' aka invokestatic on R foo(Map<String, V>
params), or we can capture functions as values and pass them around, in
which case we capture the second signature in a lambda.
For each function we just compile 3 static methods with the 3 signatures
public static CompiledTemplate foo() { return ThisClass::foo; } <-- this
is the lambda capture I am considering replacing with condy
public static Result foo(Map<String, V> m,...) { return foo(m.get("v1"),
m.get("v2"),...); }
public static Result foo(V v1, V v2,...) {...}
So all callers calling the lambda method share an instance if it changes to
use condy or doesn't. The method dispatching within the lambda is also
itself an `invokestatic` style call, so I don't think there even is a
penalty?
Since the type profiling opportunities are statically analyzable (is the
capture a virtual method? is there a signature mismatch between the
interface and the delegate?), does this imply that there are some simple
rules that the compiler could use to split the difference? or perhaps LMF
itself could opportunistically cache and reuse lambda instances when we
expect that the jit has no particular opportunities?
Or maybe this is all fraught since putting logic in the compiler or runtime
that assumes particular behavior of the JIT is just a risky proposition.
This does remind me of an odd issue I ran into with condy where I actually
wanted to split two condys that were identical to be executed twice to
preserve identity semantics. I ended up solving this by just adding dummy
parameters
<https://github.com/google/closure-templates/blob/18782276599c09ea565cb08dcc1832227797ff8f/java/src/com/google/template/soy/jbcsrc/shared/ExtraConstantBootstraps.java#L54>to
my bootstrap methods. A similar solution could be used for LMF+condy where
we preserve 'distinctly' spun classes but gain 'faster linkage'
On Sat, Oct 21, 2023 at 11:59 AM John Rose <john.r.rose at oracle.com> wrote:
> On 20 Oct 2023, at 13:59, Brian Goetz wrote:
>
> > The optimization is appealing because condy linkage is cheaper than indy
> linkage, and because it would allow more sharing between identical lambdas
> in the same file (they'd map to the same condy, which would only have to be
> resolved once.)
>
> Using unshared lambdas has a small advantage which is sometimes
> significant.
> Lambdas accumulate type profiles, and those type profiles add an extra
> hidden layer of customization to the lambdas, exploited by the JIT
> sometimes.
>
> So you might have two identical lambdas, for which the JIT produces
> completely
> different code, because it devirtualizes something in the lambda (after
> inlining the desugared body), and devirtualizes differently for the two
> different lambdas.
>
> All I’m saying here is that sharing is not always a win. Sometimes the
> opposite move, splitting and customization, is the performance win,
> even though you have two copies of the code in the end.
>
> So, Luke is proposing an interesting experiment, one which is likely to
> improve startup and footprint, but could also leave some technical debt
> to the profiler and JIT. Note also that JIT code quality impacts
> startup and warmup; you can see startup itself get worse if you do
> something the JIT doesn’t like.
>
> The fun thing about invokedynamic (unlike any other instruction) is that
> it relinks itself for every distinct occurrence of the instruction.
> (Other instructions become fully linked as soon as their CP entries
> link, so sharing or splitting the instructions does not affect the
> resolution of CP entries.) If you have two identical invokedynamic
> instructions, they incur two resolutions. This means the LMF might
> possibly spin two identical but distinct lambda classes. That might
> seem to be a waste, but there are hidden benefits. The invokedynamic
> instruction turns the default towards “split them all” while the
> condy constant turns it towards “share them all”.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20231022/cd7ed086/attachment.htm>
More information about the amber-dev
mailing list