Computed Constants API question

Per-Ake Minborg per-ake.minborg at oracle.com
Wed Aug 30 13:22:17 UTC 2023


Hi Chen,

We are looking into splitting up the auxiliary field into two separate fields. One final field for the supplier and another field for the holding of CC's state (e.g. if it was evaluated to null, a non-null value etc.).

This will make the CC objects a bit larger but will provide several other benefits including simplifying the code and improving performance.

Best, Per
________________________________
From: liangchenblue at gmail.com <liangchenblue at gmail.com>
Sent: Monday, August 28, 2023 3:37 PM
To: Per-Ake Minborg <per-ake.minborg at oracle.com>
Cc: Maurizio Cimadamore <maurizio.cimadamore at oracle.com>; Per Minborg <pminborg at openjdk.org>; leyden-dev at openjdk.org <leyden-dev at openjdk.org>
Subject: Re: Computed Constants API question



On Mon, Aug 28, 2023 at 6:30 PM Per-Ake Minborg <per-ake.minborg at oracle.com<mailto:per-ake.minborg at oracle.com>> wrote:
Hi Chen,

Thanks for trying ComputedConstants!
I'm more than glad to. We finally are able to enjoy constant-folding for array-like structures before frozen arrays arrive :)

On top of Maurizio's answers, it should be noted that we have experimented with an array similar to your suggestion early in the prototype phase
and, unfortunately, the solution became slow and had a larger footprint. Such solutions must create and hold an individual lambda
for each element and both the elements and the lambdas must be calculated eagerly.
What if "of(() -> provider.apply(t))" was changed to "ListElementComputedConstant.create(i, provider)"? Does creating the CC without creating a lambda instance incur a huge performance overhead as well? Guess I will take time and try locally with the existing benchmarks.

With the on-demand approach, startup times and footprint requirements were significantly better.

We also have a similar approach for maps that we are experimenting with. This would provide an on-demand map that is eligible for constant folding optimizations.
The on-demand map is definitely better than a non-on-demand one; it has 2 major advantages that merit its inclusion in the API now:
1. The implementation is less likely to be accidentally non-constant-foldable;
2. It will be otherwise difficult for users to implement a on-demand CC map (where each CC is on-demand)

The implementation itself won't be hard; we can create another subclass that uses a Function as a provider.

In addition, I doubt the volatile write to the provider (auxiliary) [1] suffices: according to Aleksey Shipilyov [2], since AbstractComputedConstant has no final fields, the auxiliary field might be null in a volatile read even if the constructor has returned. Can you explain how this is safe, and if read/write volatile in VarHandle differs from that in regular volatile fields?
I think this concept would be great for general lazy calculation but when and if it can make its way into the JEP is unsure.

Best, Per
No worries. We can always try out, and preview allows us sufficient usage to test out our new APIs.

Cheers,
Chen

[1] https://github.com/openjdk/leyden/blob/591689ed312977bbd6f99484d3c92e6a12aed9b3/src/java.base/share/classes/jdk/internal/constant/AbstractComputedConstant.java#L74
[2] https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#wishful-volatiles-are-finals
________________________________
From: liangchenblue at gmail.com<mailto:liangchenblue at gmail.com> <liangchenblue at gmail.com<mailto:liangchenblue at gmail.com>>
Sent: Monday, August 28, 2023 12:08 PM
To: Maurizio Cimadamore <maurizio.cimadamore at oracle.com<mailto:maurizio.cimadamore at oracle.com>>
Cc: Per Minborg <pminborg at openjdk.org<mailto:pminborg at openjdk.org>>; leyden-dev at openjdk.org<mailto:leyden-dev at openjdk.org> <leyden-dev at openjdk.org<mailto:leyden-dev at openjdk.org>>
Subject: Re: Computed Constants API question

Thanks Maurizio,
This late condensation does explain the peculiarities in the OnDemandComputedConstantList. And I think not providing a List<V> factory is fine, despite the usage complexities: we still need to track the computation state for each element, so having a CC wrapper over each element isn't too bad.

I think the OnDemandComputedConstantList implementation is unnecessary; we can just create an array of non-null ComputedConstant elements like:

ComputedConstant<T>[] array = new ComputedConstant<?>[size]; // unchecked
for (int i = 0; i < size; i++) {
    final int t = i;
    array[i] = of(() -> provider.apply(t));
}
return JUCA.listFromTrustedArray(array);

Users can use Map.ofEntries to create a Map<K, CC<V>>, but since people might use other types of maps that aren't eligible for Constant-folding, I would recommend providing an official API as well to avoid user errors.

The interloping from List<CC<V>> to List<V> (and also that for Maps) can be implemented by users if needed. It shouldn't be too much of a problem, I would assume.

Chen Liang

On Mon, Aug 28, 2023 at 5:29 PM Maurizio Cimadamore <maurizio.cimadamore at oracle.com<mailto:maurizio.cimadamore at oracle.com>> wrote:
Hi,
I believe the issues you see in the JEP reflect the fact that the API
went through a stage of "late condensation" - we used to
ComputedConstant and ComputedList, but the latter has now turned into
just a factory on the former. I think the factory provided is the more
general (as it allows for different resolution policies).

If I recall correctly, the decision _not_ to provide a List<V> factory
is motivated by the fact that we would have to respecify that List::get
is associated with the same behavior as ComputedConstant::get. That is,
that list can act in very weird ways, throw novel exceptions, etc. For
these reasons we preferred to make the CC-nature of the list apparent in
its generic type, rather than introducing some magic list wrapper which
adds its own special behavior (see Collections::unmodifiableList).

Now, with that said, I can see this going both ways - while List<CC> is
a more explicit and "honest" representation - what you say re. interop
with clients accepting just a List<V> is also a valid point (and you
can't fully get to a List<V> just by using a Steam mapper, as the
terminal operation `asList` would force eager computation of all the
constants).

Maurizio

On 28/08/2023 09:31, - wrote:
> Hello Per and Leyden subscribers,
> First, I am glad that we are finally adding an API that exposes one of
> core libraries' favorite feature, `@Stable`, to common users!
>
> For the API design, however, I have a request: Can we have a
> ComputedConstant factory that creates a List<V> in addition to one
> that creates a List<ComputedConstant<V>>?
>
> I think using the List<ComputedConstant<V>> is confusing. The example
> usages in the JEP [1] and in the API specification [2] are already
> wrong: we need an extra ConputedConstant.get() call to unwrap the
> ComputedConstant after List.get(index) call, which currently returns a
> computed constant than the actual value.
>
> The current List<ComputedConstant<V>> is to be kept in case users want
> fine-grained control over each constant's resolution failure, etc. and
> covers the new factory's functionality. But I believe the new factory
> will see wider usage:
>
> 1. None of the 2 old patterns in the "Motivation" section uses any of
> these exception handling or initialization state detection.
> 2. Returning a List<V> allows users to conveniently pass the list in
> usages instead of using streams or writing custom wrappers.
>
> A follow up to a previous request [3], I believe having a map (of type
> Map<K, V> instead of Map<K, ComputedConstant<V>>) would be feasible too.
>
> Finally, a side comment about the current
> OnDemandComputedConstantList: it computes ComputedConstant wrappers in
> addition to the actual constants on demand, which... seems a bit
> overkill, when ComputedConstant itself is already a lightweight
> wrapper of a heavy computation?
>
> Best,
> Chen Liang
>
> [1]: https://openjdk.org/jeps/8312611  "var kbd = lbl.labels.get(3);"
> [2]:
> https://cr.openjdk.org/~pminborg/computed-constant/api/java.base/java/lang/ComputedConstant.html#of(int,java.util.function.IntFunction)
>  "return PO2_CACHE.get(n);"
> [3]: https://mail.openjdk.org/pipermail/leyden-dev/2023-August/000277.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20230830/d6904c9d/attachment.htm>


More information about the leyden-dev mailing list