P.S.C. (post-send clarification) > The workflow would be: > > static final MethodHandle MH_ensureInit > = publicLookup().findVirtual(L…, “ensureInitialized”…); >
By that I mean the workflow of the dynamic language implementor. And after hitting “send” I realized that optimizing that one case (of a findVirtual -> bindTo -> bindTo) is harder than I thought. The entire workflow below could instead be a call to a wrapping function that takes an arbitrary “mh” (as below) and wraps an init-barrier onto the front *if needed*. It would have to take a Lookup and a Class, plus the mh. It would handle all the internal stuff. If the user wanted a bare init MH, just pass in an empty MH as a “seed”. And maybe take a short-circuit action if the “seed” comes back unchanged; this is an alternative to isFullyInitialized, but it seems sneaky. class Lookup { … /** * To the given method handle, prepend an action, if necessary, to trigger * initialization of the given class the first time the method handle is called. * If it would be illegal to call ensureInitialized on the given class from this lookup, * immediately report an error. Otherwise, if the class is already fully initialized * return the method handle unchanged. Otherwise, return a new method handle * (of the same type) which incorporates the necessary initialization action, * as if by a call to ensureInitialized. */ MethodHandle ensureInitialized(Class target, MethodHandle mh) { checkAccess(target); if (isFullyInitialized(target)) return mh; // we need to tack a “before action” onto mh to trigger inits: MethodHandle before = MH_ensureInit.bindTo(target); return collectArguments(mh, 0, before); } // note: IMPL_LOOKUP requires previous checkAccess call private static final MethodHandle MH_ensureInit = publicLookup().findVirtual(L…, “ensureInitialized”…).bindTo(IMPL_LOOKUP);