On Oct 27, 2016, at 9:07 AM, mark.reinh...@oracle.com wrote:
> 
> Further comments most welcome, as usual!


+100 for *qualified* opens; this puts an important limit on deep reflection.

My main concern with reflection is to avoid "falling off the encapsulation 
cliff"
the first time a user module wishes to open itself up for deep reflection.
By such a "cliff" I mean that when deep reflection is allowed, potentially
any name in the module can be inspected.  Even of only 0.01% of names
are actually inspected, tools for reorganizing code must assume that 100%
of the names *might* be inspected, at some point in the future, by the
allowed party.

So qualified opens is a partial solution.  And, I think it is exactly right for
today, because it can be extended tomorrow.  I.e., it is future-friendly.
I'll explain by sketching a concept called "moderate reflection", or "MR".

A fuller solution would allow other tools to make conclusions about more
specific limitations on the actual extent of the deep reflection.   Call such
an extent-limited reflection moderate reflection, where "moderation" is
declared statically by some sort of flexible declarative rule set.  In this way
tools could make more detailed conclusions about the encapsulation of
particular names in the module.

 For future JDK releases we can consider layering  of this qualified opens,
by creating a trusted, parameterized meta-framework ("Moderate Reflection")
to which a user module can be qualified-open.  This meta-framework can
then perform deep reflection on behalf of self-describing "moderately 
reflecting"
client frameworks.  User modules would not directly open themselves to any
module other than MR.

The advantage would come when the client frameworks explicitly declare their
self-restraint ("moderation") in reflection.  For example, the "Foo" framework
might limit itself to names annotated with @FooFrameworkHook.

An AOT compiler (or other jlink-time reorganization tool) would (1) note that
some user module bar is qualified-open only to Moderate Reflection, and
has an export (maybe qualified) to a Foo framework.  At runtime, (2) the
Foo framework would ask Moderate Reflection to reflect into bar.
Moderate Reflection would (3) check the self-limitation on Foo, and also
ensure that bar exports (though doesn't open) to Foo.  MR would then
gain the requested access and delegate it back to Foo.  Finally, (4) the
AOT compiler would free itself to omit metadata for unexported names
not visible to moderate reflection.

(Method handles are a good way to grant access, since they can
be delegated from MR to Foo without re-authorizing Foo.  Core
Reflection re-authorizes on every access, which awkwardly
requires deep reflection on usage, as well as initial lookup.)

Moderate Reflection might also look at metadata on the bar module
(besides its module exports) to impose further limits on reflection.
Thus, MR-specific metadata might prevent MR from granting bar
access to normally-trusted frameworks that bar doesn't trust, if
bar can blacklist them for itself in a place that MR checks.

And so on.  None of this needs to be built into the module system.
To gain the benefit of it, basic parametric policies need to be implemented,
adopted by client frameworks, and used by tools to perform optimizations.

A typical optimization is "tree shaking", where a class or method that is
never used is dropped from the application.  Or, if it is used in a way that
can be inlined locally, the metadata can still be dropped.  In either case,
making code go dead is an important ingredient to many optimizations.

— John

Reply via email to