projectodd/rephract — pull request #5 by t-beckmann (2013-12-19 08:14:45+00:00)
Title: Extract value of static final fields once instead of fetching it on each access.

With rephract 1.0.0 I had a problem analysing interfaces having fields in them. In Java 7 Update 10 it ran fine, but in Update 45 the code broke. Here, lookup.unreflectGetter() fails miserably. The reason is in the JRE implementation of the DirectMethodHandle constructor, see below. The section titled corner case contains a call to member.getMethodType() which will throw if the member is not a method but a field. As a result rephract 1.0.0 failed to create the getter and since it analyses an entire hierarchy at once, any class implementing an interface with some field in it became entirely inaccessible.

For some reason rephract 1.1.0 is no longer affected by this JRE bug, yet my fix developed makes sense still. The code change causes static final fields to be extracted just once when the type is analysed. The value is then returned as constant instead of readout on each use.

Thus, for rephract 1.1.0 this could be a minor optimization making the code somewhat more robust to future changes. I suggest merging it although it's not strictly necessary. Maybe you know the reason why rephract 1.1.0 is not affected better than me. Notice, I read much of the code and actually quite like it...

Regards,
Thomas.

class DirectMethodHandle extends MethodHandle {
final MemberName member;

// Constructors and factory methods in this class *must* be package scoped or private.
private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
super(mtype, form);
if (!member.isResolved())
throw new InternalError();

if (member.getDeclaringClass().isInterface() && !member.isAbstract()) {
// Check for corner case: invokeinterface of Object method
MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
if (m != null && m.isPublic()) {
member = m;
}
}

this.member = member;
}
...