RFR(s): 8244733: Add ResourceHashtable::xxx_if_absent (was: ResourceHashtable::compute_if_absent)
David Holmes
david.holmes at oracle.com
Mon May 18 02:04:27 UTC 2020
Hi Thomas,
A bit of a long winded reply as I walk through the motivation here ...
On 14/05/2020 6:08 pm, Thomas Stüfe wrote:
> Hi,
>
> This is a continuation of the review thread:
> https://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2020-May/039444.html
>
> I changed the title of the bug somewhat hence the new thread.
>
> JBS: https://bugs.openjdk.java.net/browse/JDK-8244733
> Webrev:
> http://cr.openjdk.java.net/~stuefe/webrevs/8244733--add-resourcehashtable--compute_if_absent/webrev.01/webrev/
>
> This now adds three new functions to ResourceHashTable:
>
> new_if_absent(), compute_if_absent(), put_if_absent()
>
> which work very similar to their equivalents in j.u.Map.
>
> The advantage they offer is that for a typical "if map does not contain
> X, add X+value" pattern we only do the lookup once.
>
> --
>
> So I extended the scope of the item. After playing around with various
> call sites I realized that David's proposal of put_if_absent() would be
> useful, as well as a variant which just adds a default constructed
> value. All three are tested in gtest and used in real call sites.
The advantage of only doing the lookup once is achieved with a simple
put_if_absent method.
The downside of put_if_absent is that you have to precompute the new
value, even if you don't need it. Hence the desire for compute_if_absent.
But in C++ compute_if_absent needs to be able to execute a mapping
function which can be expressed based only on global state and the key
that was passed in. (Whereas in Java we can create an inner class that
implements the functional interface, and it has implicit access to the
enclosing instance to use any state needed in the calculation.)
Hence you introduced new_if_absent() as well - though I'd be tempted to
call it put_default_if_absent(). The new_if_absent function knows how to
create a default instance of the value and returns a pointer to that
instance - and the calling code can then compute and set the real value.
So walking through BytecodeConstantPool::find_or_add as an example:
u2 BytecodeConstantPool::find_or_add(BytecodeCPEntry const& bcpe) {
u2 index;
u2* probe = _indices.get(bcpe);
if (probe == NULL) {
index = _entries.length();
_entries.append(bcpe);
_indices.put(bcpe, index);
We can use put_if_absent quite easily here:
u2 BytecodeConstantPool::find_or_add(BytecodeCPEntry const& bcpe) {
bool created = false;
u2 index = _entries.length();
u2* probe = _indices.put_if_absent(bcpe, index, &created);
if (created) {
_entries.append(bcpe);
}
But lets assume _entries.length() requires a traversal to calculate
(rather than a simple lookup) in which case you want to avoid
calculating it unnecessarily. So we want compute_if_absent() except we
don't have a way to factor computing this->_entries.length() into a
function object. So we use new_if_absent():
u2 BytecodeConstantPool::find_or_add(BytecodeCPEntry const& bcpe) {
u2 index;
bool created = false;
u2* probe = _indices.new_if_absent(bcpe, &created); // set default
value
if (created) {
index = _entries.length();
_entries.append(bcpe);
*probe = index; // set real value
So if you accept the premise that it is undesirable to pre-determine the
value if you don't end up adding the map entry, then the need for
compute_if_absent and thus new_if_absent becomes clear. If you don't
accept that premise then put_if_absent is all you need**.
** And put_if_absent can also partly avoid the computation overhead if
it can split the creation of a default value and the calculation and
setting of the true value (not applicable if the value is a primitive
type of course).
I'm not clear in all the examples in the webrev whether avoiding the
computation makes any practical difference. If _entries.length() just
loads a field then I would argue that new_if_absent is overkill for that
case. OTOH avoiding construction of a
ClassLoaderStats/DumpTimeSharedClassInfo instance may be more
significant as we have to free it again if not used.
So overall I understand the motivation for the more elaborate API and
the way you have applied it so far.
Thanks,
David
> Ran tests tonight in our CI, all went through.
>
> Thanks, Thomas
>
>
More information about the hotspot-runtime-dev
mailing list