MethodHandles.Lookup and modules

Alex Buckley alex.buckley at oracle.com
Sat Dec 19 00:44:51 UTC 2015


On 12/18/2015 12:20 AM, John Rose wrote:
> On Dec 17, 2015, at 6:01 PM, John Rose <john.r.rose at oracle.com
> <mailto:john.r.rose at oracle.com>> wrote:
>>
>> I think I would prefer case 2. The user model is PUBLIC is the
>> weakest (non-empty) access mode available to bytecode behaviors. As
>> such it respects the LC's position in the module graph, and
>> excludes module-private, package-private, and class-private.
>> UNCONDITIONAL is the special thing provided by publicLookup, which
>> ignores the module graph. Then PACKAGE opens up the LC's package,
>> MODULE opens up the LC's module, and PRIVATE opens up the LC itself
>> (plus its nestmates). Feels pretty good, especially since MODULE
>> and PACKAGE continue to have a parallel sense of restriction.
>>
>> What do you think?
>
> So I caught you in the hall and we talked, and this seems agreeable
> to us both, perhaps with a name change to UNCONDITIONAL, and also a
> distinctionbetween PUBLIC and QUALIFIED (as you originally proposed).
>
> To try and tease out some symmetry here:
> - Always, any type T is accessible to itself, when T = LC.
> - PACKAGE mode: Any type T is accessible (within its own package), when
> PACKAGE(T) = PACKAGE(LC).
> - MODULE mode: A public type T is accessible (within or beyond its
> package), when MODULE(T) = MODULE(LC).
> - QUALIFIED mode: A public type T is accessible beyond its module, when
> IS_CE(T, LC),
>      where IS_CE(T, LC) = IS_CONDITIONALLY_EXPORTED(PACKAGE(T),
> MODULE(LC)) and MODULE(LC) READS MODULE(T).
> - PUBLIC mode: A public type T is accessible beyond its module friends
> when IS_UE(T, LC),
>      where IS_UE(T, LC) = IS_UNCONDITIONALLY_EXPORTED(PACKAGE(T)) and
> MODULE(LC) READS MODULE(T).
>
> These conditions can be tested independently.  PACKAGE implies MODULE,
> but everything else is disjoint.
>
> Also:
> - UNCONDITIONAL: In this mode, a type T is accessible if
> IS_UNCONDITIONALLY_EXPORTED(PACKAGE(T)), regardless of LC.
> - PRIVATE/PROTECTED: These protection modes apply only to non-types (JVM
> does not enforce "private" on classes).
> - NOACCESS: This is not a mode but the absence of any combination of
> modes; no access is allowed.

So let's recap full power lookups:

- Start with an arbitrary class in an arbitrary module calling 
MethodHandles.Lookup.lookup() to get a "full power" lookup object L. L's 
lookup modes are PUBLIC + QUALIFIED + MODULE + PROTECTED + PACKAGE + 
PRIVATE.

- The arbitrary class obtains a Class object representing class A, then 
calls L.in(A). If L's lookup class cannot access A (for example, A is 
package-private in a different package than L's lookup class), then the 
resulting lookup object has lookup mode NOACCESS. Otherwise:

   -- If A is in a different module than L's lookup class, then the 
resulting lookup object has lookup mode NOACCESS.

   -- If A is in the same module as L's lookup class, but a different 
package, then the resulting lookup object has lookup modes no greater 
than PUBLIC + QUALIFIED + MODULE.

   -- If A is in the same module as L's lookup class, and in the same 
package, but A is a different class than L's lookup class, then the 
resulting lookup object has lookup modes no greater than PUBLIC + 
QUALIFIED + MODULE + PACKAGE.

   -- If A is nested in the same package member as L's lookup class, 
then the resulting lookup object has lookup modes no greater than PUBLIC 
+ QUALIFIED + MODULE + PACKAGE + PRIVATE.

   -- If A is the same class as L's lookup class, then the resulting 
lookup object has the same lookup modes as L.

> The publicLookup should have UNCONDITIONAL and PUBLIC set. An
> original full-power lookup does *not* have UNCONDITIONAL set, just
> PUBLIC. The purpose of UNCONDITIONAL is to allow publicLookup to be
> unconcerned (as documented) about its LC. We can restore LC to be
> java.lang.Object.

Since PUBLIC is just UNCONDITIONAL with a concern for readability, it's 
surprising that publicLookup cares about PUBLIC.

Before saying any more about that, let me take a small detour. I seem to 
recall an intent to specify the public lookup object as representing an 
(undisclosed) lookup class in the unnamed module ... if so, then since 
the unnamed module reads all named modules by decree, we have 
UNCONDITIONAL+PUBLIC as trivially equal in access power to PUBLIC, and 
we don't need UNCONDITIONAL at all ... if not, then publicLookup could 
be UNCONDITIONAL only.

Returning from the detour ... does the public lookup object have PUBLIC 
solely so that it can teleport to give new lookup objects which drop 
UNCONDITIONAL but still retain the interesting PUBLIC mode?

Proceeding to walk through a publicLookup:

- Start with an arbitrary class in an arbitrary module calling 
MethodHandles.Lookup.publicLookup() to get a public lookup object PL. 
PL's lookup mode is UNCONDITIONAL [+ PUBLIC?].

- The arbitrary class obtains a Class object representing class A, then 
calls PL.in(A). If PL's lookup class cannot access A [I'm not sure what 
PL's lookup class is, but it seems plausible that it can't access A], 
then the resulting lookup object has lookup mode NOACCESS. Otherwise:

   -- If A is in a different module than PL's lookup class, then the 
resulting lookup object has lookup mode UNCONDITIONAL. ???

  -- If A is in the same module as PL's lookup class, then the resulting 
lookup object has lookup mode PUBLIC. ???

> As an odd use case, a stripped lookup with only PACKAGE modes
> will be able to see any package-mate T of LC, and any package-private
> API point T.M, but it won't be able to query anything *outside* of the
> package of T.  Unfortunately, it also won't be able to query any public
> member T.M, unless the PUBLIC bit is present.  So I suppose stripping
> MODULE and QUALIFIED, leaving PUBLIC and PACKAGE, would
> provide useful access to T.M even if M were public.

I think there's an "old" meaning of PUBLIC floating around here. Now 
that PUBLIC pertains to public types _in unconditionally exported 
packages_, it shouldn't relate to intra-package access, since for such 
access you don't care if the package is exported. It's now MODULE that 
accesses public types within the module, so arguably, access to a public 
member M of package-mate T should be possible with lookup modes 
MODULE+PACKAGE, not PUBLIC+PACKAGE.

Alex


More information about the jigsaw-dev mailing list