Review Request: JDK-8235521: Replacement API for Unsafe::ensureClassInitialized
John Rose
john.r.rose at oracle.com
Thu Jun 4 23:21:29 UTC 2020
On Jun 3, 2020, at 7:38 PM, Mandy Chung <mandy.chung at oracle.com> wrote:
>
> On 6/3/20 6:24 PM, John Rose wrote:
>> On Jun 3, 2020, at 5:16 PM, Paul Sandoz <paul.sandoz at oracle.com <mailto:paul.sandoz at oracle.com>> wrote:
>>>
>>> if (UNSAFE.shouldBeInitialized(cls)) {
>>> UNSAFE.ensureClassInitialized(cls);
>>> }
>>>
>>> Although it seems redundant to perform the check, suggesting it is not needed.
>>
>> It’s useful (IIRC) in this kind of code:
>>
>> MethodHandle mh = … something about cls ...;
>> if (!UNSAFE.shouldBeInitialized(cls))
>> return mh;
>> // Oops, every eventual call to mh needs to do the check:
>> return filterArguments(mh, 0, UNSAFE_ensureClassInitialized.bindTo(cls));
>>
>
> It is useful for method handle machinery. I don't see the need to expose it as a supported API for java applications/framework.
>
> Maybe useful for dynamic languages?
Yes, it would be. Since it’s a longer conversation, I suggest making
a *non-public* API point on Lookup, isFullyInitialized(Class).
Further suggestions:
See DirectMethodHandle.ensureInitialized for the use of both
Unsafe API points in concert; it has ticklish states involving
blocking on the thread doing the initialization. I don’t want to
expose that yet.
But, factor all uses of those two Unsafe API in DMH.java through
the new Lookup API points, a public ensureInitialized (I like that
name best; it’s the one adopted internally to java.lang.invoke) and
also through a new non-public isFullyInitialized. To avoid access
checks use IMPL_LOOKUP.
Note the inverted boolean sense. The idea is that if isFullyInitialized
returns true, then there’s no point in arranging for future calls to
ensureInitialized.
If there is true demand for the second API point we can roll it out as
public. But there’s a catch: There’s a third initialization state,
“being initialized” which a dynamic language will also want to care
about. So there’s a need for a third API point of some sort, not covered
by the second.
Here’s a quick thought about that third API point: As things stand,
we are going to allow Lookup.findVirtual to apply to Lookup::ensureInitialized
to return a suitable access point, for future use, for anyone to use to
“tweak” any given class (modulo access restrictions). Good. We can
secretly add an optimization to the particular MH (and no other) so
that it uses the same machinery as MH’s returned for static getters
and setters and invokers that incorporate an init-barrier.
I’m not saying do this now, but maybe file a follow-up bug to add
that optimization to the resulting MH for Lookup::ensureInit,
if and when we add Lookup::isFullyInitialized. That will give
the dynamic language people the same “hooks” we enjoy internally.
The workflow would be:
static final MethodHandle MH_ensureInit
= publicLookup().findVirtual(L…, “ensureInitialized”…);
MethodHandle mh = …;
Class target = …;
if (!lookup().isFullyInitialized(target)) {
// we need to tack a “before action” onto mh to trigger inits:
MethodHandle before = MH_ensureInit.bindTo(lookup()).bindTo(target);
mh = MethodHandles.collectArguments(mh, 0, before);
}
return mh;
— John
More information about the core-libs-dev
mailing list