Classfile representation of specializable classes
Brian Goetz
brian.goetz at oracle.com
Fri Jul 11 16:58:32 UTC 2014
We can think of a specializable class:
class Box<any T> {
T t;
public Box(T t) { this.t = t; }
public T get() { return t; }
}
as being both a class (we're used to compiling the above into an erased
class for reference instantiations of T) and a template (for specialized
instantiations.)
We have a range of options for what javac could produce this class:
- A template file only, from which both specialized instantiations
(Box<int>) and erased instantiations are derived;
- An erased class file (like we do today) plus a template file (where
the erased version is technically unnecessary, but statically generated
as an startup-time optimization)
- An erased class file with a template embedded in it, accessible via
reflection
- An erased class file with attributes identifying how to transform it
into a specialized class (this was the example given in the writeup.)
Further, the notion of "template" itself ranges over many possible
options. (Note that it is not a goal to produce a feature like
Expression Trees.)
The example in the writeup has many pleasing properties (one artifact,
so can't get out of sync; encode minimal additional metadata needed to
efficiently transform an erased classfile to a specialized classfile;
the "template" can be used as an erased classfile as is, just by
ignoring the specialization metadata attributes.)
It also has an unpleasant property: the bytecode for an already loaded
class is not available easily through its classloader or reflection,
meaning that a runtime specialization mechanism would have to jump
through hoops (e.g., retransform-classes) to get at the bytecode. Since
specializing a class under this scheme requires, as input, the bytecode
of the original class, this could become problematic for classes that
are themselves generated (i.e., not findable with
ClassLoader.getResource("Foo.class")).
The factors being traded off here are:
- classfile size -- the classfile+template approach would be ~2x the
size of the classfile alone; other approaches might be as little as a
few percent bigger
- startup cost -- deriving the erased classfile from a template costs
us startup time, and the "load erased classfile" use case isn't going
away any time soon
- specialization cost -- some template forms are cheaper than others
to generate bytecode from
- security -- exposing the bytecode directly may have security
consequences
For the initial prototype, which will operate by offline classfile
transformation, any of these will do, so for that we should do the
simplest thing that gets us to a prototype. But we should also continue
to evolve the representation story.
More information about the valhalla-dev
mailing list