Selectively Shifting and Constraining Computation
Mark Reinhold
mark.reinhold at oracle.com
Fri Oct 28 00:28:41 UTC 2022
2022/10/21 19:49:36 -0700, Dan Heidinga <heidinga at redhat.com>:
> Thanks for posting this document. It provides a clear starting point for
> us to move forward to start to address Leyden.
Thanks, Dan, and thanks for your comments and questions.
> A few questions based on my read through:
>
>> As long as a condenser preserves program meaning and does not impose
>> constraints other than those accepted by the developer, an implementation has
>> wide latitude to optimize the result.
>
> Does “an implementation” refer only to the JDK or are other parts of the
> ecosystem - frameworks, libraries, etc - able to add their own condensers
> as well?
Good question!
We’re concerned here primarily with any software system that’s claimed
to be a conformant implementation of the Java Platform -- the JDK is
merely the dominant and best-known example. The components of such a
system -- including any condensers -- can be held to the rigors of the
Platform Specification and the JCK, thereby ensuring that they preserve
the meanings of Java programs.
Some people will, no doubt, want to write their own condensers, and
obviously we’d like all condensers to preserve program meaning. The
current conformance regime (specification/RI/JCK), however, applies only
to entire Platform implementations. If we want to enable developers of
external condensers to make certifiable claims of safety then we’ll need
to extend the conformance regime to test standalone condensers.
(Whether that needs to be a priority isn’t clear to me at the moment.)
Enabling the foundational tooling of the JDK (jlink, or whatever) to run
arbitrary condensers is attractive, but not without risk. People could
ship non-conformant condensers even if we extend the conformance regime,
since there’d be no conformance requirement. Developers could, perhaps
unwittingly, use such condensers and wind up with broken programs. So
maybe we’ll support external condensers in the JDK toolchain but emit a
warning when they’re used.
>> If a developer chooses condensers that shift sufficient computation from run
>> time to earlier phases — which may require accepting many constraints — then
>> a conforming Java implementation could even produce a fully-static
>> platform-specific executable.
>
> Great to read this! Especially in light of the recent announcement around
> GraalCE moving under the OpenJDK umbrella, this provides wide latitude to
> use something like Graal’s native image as a final condenser.
Exactly.
> ...
>
>> Some of these techniques might not require any specification changes, e.g.,
>> expanding dynamic-proxy call sites into ordinary bytecode prior to run time.
>
> My experiments in this area have shown that the specification doesn’t need
> to change, but that there are user-visible changes when doing this (ie:
> Class:getNestMembers and others). Is there an intention to document the
> user visible aspects of changes from Condensers?
To the extent that a condenser changes the behavior of a program within
the bounds of the (possibly enhanced) Platform Specification then yes,
we should document those changes.
>> Others will definitely require specification changes, e.g., resolving classes
>> prior to run time. Yet others will take the form of new platform features
>> that allow developers to express temporal shifting directly in source code,
>> e.g., lazy static final fields.
>
> Glad to hear that language changes are in the scope of this proposal.
> Helping developers say what they mean makes it easier to reason about what
> needs to change versus trying to impose new semantics on top of the soup
> that is <clinit>.
Indeed! Applying new semantics to existing code always leads to tears.
>> So let’s generalize, and allow an arbitrary number of phases in which
>> time-shifting transformations and related optimizations can be applied.
>
> To confirm: this is saying that a “condensed” Java application may act as
> an input to a later phase of “condensation”?
Yes, for some but likely not all definitions of “condensed.” If you’ve
condensed all the way down to a platform-specific executable, e.g., then
it’s likely not worth the effort for us to support further condensation.
(I suspect it’ll be acceptable to consider condensation to such formats
to be terminal steps, as you suggest above.)
>> Condensation is meaning preserving.
>
> Have you given thought to precisely specifying and then validating this
> property? It’s definitely something we want but it may be challenging to
> enforce….
The meaning of a Java program is already given by the Specification, and
the JCK already validates a Java implementation by running a large
collection of Specification-derived tests. My initial thought here is
to extend the JCK to test a condenser by applying the condenser to each
JCK test and then verifying that the condensed test still passes. (To
keep JCK run times tractable, do this in large batches.)
>> To ensure that condensers run code correctly, and transform and constrain
>> code only in ways that preserve meaning, we must add the concept of
>> condensers to the Java Platform Specification.
>
> I’m unclear reading this if the set of Condensers will be limited to what
> an implementation chooses to provide or if others (frameworks) can provide
> their own Condensers as well?
(See above.)
> Currently, implementing a jlink plugin from outside the platform is a pain
> (though possible with enough –add-opens and reflective hacks) but I’d
> prefer to see Condensers have a more supported api so the ecosystem can
> extend the concept.
Agreed. We probably do want an open condenser API, though designing a
good one will take considerable effort. (We didn’t open the jlink
plugin API because we knew that it wasn’t ready.)
>> We can, however, enable other Java implementations (e.g., some future version
>> of the GraalVM native-image tool) to do so.
>
> This is prescient given the recent announcement that Graal CE is moving to
> OpenJDK =)
What a coincidence!
>> Eliminate apparently-unused classes and class members (i.e., stripping, which
>> requires the constraint that selected classes and members cannot be reflected
>> upon)
>
> Being slightly pedantic, it means the removed members can’t be reflected
> on, correct?
Yes, but ...
> A class that’s been stripped of unused methods / fields can
> still have its remaining members reflectively looked up is my assumption.
That’s a reasonable assumption.
In detail, though, we could in principle retain reflective metadata even
for removed program elements, if there’s a need to do so. We could,
likewise, remove reflective metadata for some retained program elements
if we’re confident that those elements will never be reflected upon.
More exploration required ...
>> jlink
>
> Using jlink is the natural starting point for this work. It would be
> unfortunate if condensers were limited to only work on modules given the
> (unfortunately) slow update of them. Is the intention to extend jlink to
> work with classpath entities (ie: non-modular code) as well? We foresee
> the need for condensers to be able to “condense” non-modules as well.
The jlink tool doesn’t support arbitrary class path code, or automatic
modules, in order to guarantee that the resulting image is structurally
correct by construction. I’m reluctant to give up on that guarantee.
Viable workarounds exist for non-modular code (jdeps, ModiTect, etc.),
so developers who want to risk building a potentially-broken image from
a potentially-broken class path can do so, at their option.
I do expect that, in Leyden, we’ll find interesting ways to leverage the
constraints already imposed by modules. Hopefully that will motivate
the further adoption of modules.
> We’re excited to start working with you on this approach. When do you
> think we’d be ready to create a Leyden repo and start developing the code
> for this approach?
I’m in the process of setting up a repo; more on that soon.
- Mark
More information about the leyden-dev
mailing list