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