On 01/09/2013 01:19 PM, Aleksey Shipilev wrote:
Good stuff.

On 01/07/2013 02:46 AM, David Holmes wrote:
http://cr.openjdk.java.net/~dholmes/8005232/webrev/
Sorry for obnoxious first-time reviewer questions:
  a) I think the CAS loop in newReflectionData() is misleading in its
reuse of the parameters. Can we instead inline it? Or, can we read the
fields for $reflectionData and $classRedefinedCount, with no parameters
passed?
It was originally written as one method. Performance tests showed that some (i think two more) of the public API methods were more aggressively in-lined when split in two methods. I think it would not hurt performance practically if the original variant was used.
  b) Had we considered filling up the complete ReflectionData eagerly on
first access? This will make ReflectionData completely final. I would
guess this goes against the per-use laziness?
Certainly there are usages where only one part is ever needed. For example only getDeclaredXXX but not getXXX which also triggers loading in superclasses and then aggregating...
  c) What's the merit of using Unsafe instead of field updaters here?
(Avoiding the dependency on j.u.c?)
Mainly because of initialization-loops. AtomicReferenceFieldUpdater uses Class.getDeclaredField(name), which in turn needs ReflectionData, ... Strictly speaking, CAS is actually not needed here. Since we keep classRedefinedCount snapshot inside the ReflectionData, any races that would install "older" ReflectionData over "newer", would be quickly caught at next invocation to reflectionData(). So if there are any objections to usage of Unsafe, it can be removed and replaced by simple volatile write.
  d) I think the code can be further simplified if we stick with
reflectionData() returning non-null object all the time, and check for
useCaches instead in the usages, at the expense of creating the methods
which actually get the reflection data.
I don't quite understand what you mean. Are you suggesting to double all the methods with variants that don't use reflectionData? If you check the usages you can see that the "caching aspect" is tested at two places in each method, the rest of code is the same for caching/non-caching variants.
  e) Should useCaches be final? That will allow aggressive optimizations
for (c).
Again the initialization order issues (see checkInitted()). The value for useCaches comes from system properties. Might be final and be later overwritten via Unsafe, but wouldn't this defeat optimizations? (or if not, wouldn't then those optimizations take the wrong code-path?)

Regards, Peter


This is a saving of 7 reference fields ie. 28 bytes, resulting in a new
Class instance size of 80 bytes. This saves a further 4 bytes due to the
fields being 8-byte aligned without any need for padding. So overall we
save 32 bytes per class instance.
Shameless promotion follows. This tool [1] should help to estimate the
class layout in the face of object alignment, compressed references,
paddings, alignment and whatnot.

-Aleksey.

[1] https://github.com/shipilev/java-object-layout/


Reply via email to