Computed Constants API question
-
liangchenblue at gmail.com
Mon Aug 28 13:37:49 UTC 2023
On Mon, Aug 28, 2023 at 6:30 PM Per-Ake Minborg <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 <liangchenblue at gmail.com>
> *Sent:* Monday, August 28, 2023 12:08 PM
> *To:* Maurizio Cimadamore <maurizio.cimadamore at oracle.com>
> *Cc:* Per Minborg <pminborg at openjdk.org>; leyden-dev at openjdk.org <
> 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> 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/20230828/10c8260b/attachment.htm>
More information about the leyden-dev
mailing list