Clarifying record reflective support

John Rose john.r.rose at oracle.com
Tue Dec 3 16:35:14 UTC 2019


This thread feels correct to me.

I like the consistency with isArray/getComponentType, even though the nulls feel old fashioned.

The fast check of the direct super as jl.Record is a reasonable analogy to ACC_ENUM,
although in hindsight maybe we should have just gated enum-ness on a direct super
of jl.Enum.  (Or a second-to-direct super.  Hmm; that happens also.)  The class file
parser implementation does not check the supers of enums, in any case.  We can
transition to ACC_RECORD in the future if that turns out to be important; I hope
it doesn't.

I have two concerns concerning JVM behavior:

1. Keep class file loading fast and simple.  Don’t go beyond precedent in structure checking.
The current implementation is good from this POV; it just ensures basic referential
integrity at the constant pool level, plus shallow syntax checking of names and descriptors.
Attributes are bundled up for later, as usual.

2. Perform deeper checks only when reflection is performed.  This is when things get
sticky.  There are many things which can go wrong during reflection on a class file
that has passed all the (relative shallow) load-time checks.  If a field or method descriptor
mentions a type which cannot be loaded, reflecting that field will fail, even though the
bytecodes are perfectly serviceable (as long as the unloaded type is only used to pass
nulls in bytecode execution).  The same is true for non-loadable types in InnerClasses.
If a generic signature syntax is wrong, you find out during reflection.  We could try to
test for such things earlier, but that would slow down application startup, which is a
weak spot for us, that we don’t want to weaken further.

The application of point #2 to records is that a record component which has a
non-loadable type descriptor should fail (with a low-level error) on reflection,
even though the record can be used for normal bytecode execution.  Likewise,
if a bogus record component mentions a field that doesn’t exist, this should
(I think) fail at reflection time; there’s no reason to check for this particular
error at earlier class load time.  And so on for any other structural problems
that can happen with records.

The upshot of this is that reflective APIs should be allowed to throw low-level
errors if the class file has a deep error in it.  Such errors cannot *all* be ruled
out at class load time (in principle, not just practically; details on request),
and so reflection *must* be allowed to be an incomplete operation.

This subtly affects the reflective API points which return information that
depends on classfile attributes (when, as is often the case, such attributes cannot
be fully validated at class load time).  Such API points as getInnerClasses and
getRecordComponents must be allowed to throw errors for “partially broken”
class files.

(Do we need a specific term for “partially broken” here? We might say
“reflectively invalid” I suppose.)

The javadoc is relatively silent about reflectively invalid class files,
but don’t take that as evidence that failure is impossible.

Should getRC document failure modes?  Maybe, but if they are just the
same as those affecting getMethods, getInnerClasses, etc., there’s no need
to.  New failure modes, such as “record component not found”, might be
documented, maybe.  (I don’t see this happening in the JVM code, which
is a good sign.)  But *all* such errors are artifacts introduced by
broken tools, and it appears that they are sufficiently rare that they
can be swept under the rug, in the javadoc.  After all, errors need not
be documented, especially endemic ones like OOME and SOE, and
the reflection doc creates CNFE with a similar level of silence.

I don’t have an opinion about what javac should do with reflectively
broken class files, except that it should keep on doing what it does
today in similar situations when other attributes are reflectively
broken.

— John

P.S. Regarding the implementation, I see nothing wrong with the JVM
code as it stands today.  It implements a reasonable specifiable behavior.



More information about the amber-spec-experts mailing list