[RFR] (M) 8143608: Don't 64-bit align start of InstanceKlass vtable, itable, and nonstatic_oopmap on 32-bit systems

Dmitry Samersoff dmitry.samersoff at oracle.com
Tue Dec 15 12:11:12 UTC 2015


Chris,

1. Please file a separate CR for SA (assign it to me) and go ahead with
your fix when it become ready.

2. As far as I understand the fix, you just removed explicit alignment
for all platforms (not only 32bit) and rely on compiler. I'm a bit
scared with it (see David's comments).

Also please contact SQE (Leonid Mesnik) about testing of the fix before
pushing it.

-Dmitry


On 2015-12-11 00:31, Chris Plummer wrote:
> Hi Mikael,
> 
> See comments inline below:
> 
> On 12/9/15 8:48 AM, Mikael Gerdin wrote:
>> On 2015-12-08 20:14, Chris Plummer wrote:
>>> [Adding serviceability-dev at openjdk.java.net]
>>>
>>> Hi Mikael,
>>>
>>> Thanks for pointing this out. I'll look into it some more. Are there any
>>> tests that should be failing as a result of this? I get the feeling no,
>>> since I see other issues here that existed before my change. For
>>> example, this code is not returning the proper size if the class is
>>> anonymous or is an interface. It needs to add 1 extra word in that case.
>>> See size() in instanceKlass.hpp.
>>>
>>> Another difference from the VM code is alignObjectSize() is being used
>>> by getSize(), but headerSize is set using alignObjectOffset(). The VM
>>> code uses align_object_offset in both cases.
>>>
>>>    // Align the object size.
>>>    public static long alignObjectSize(long size) {
>>>      return VM.getVM().alignUp(size,
>>> VM.getVM().getMinObjAlignmentInBytes());
>>>    }
>>>
>>>    // All vm's align longs, so pad out certain offsets.
>>>    public static long alignObjectOffset(long offset) {
>>>      return VM.getVM().alignUp(offset, VM.getVM().getBytesPerLong());
>>>    }
>>>
>>> So the difference here is in the use of getMinObjAlignmentInBytes (not
>>> what the VM does) vs getBytesPerLong (what the VM uses):
>>>
>>>    public int getObjectAlignmentInBytes() {
>>>      if (objectAlignmentInBytes == 0) {
>>>          Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
>>>          objectAlignmentInBytes = (flag == null) ? 8 :
>>> (int)flag.getIntx();
>>>      }
>>>      return objectAlignmentInBytes;
>>>    }
>>>
>>> So this seems wrong for use in any InstanceKlass size or embedded field
>>> offset calculation. It is probably a remnant of when class metadata was
>>> stored in the java heap, and the size of InstanceKlass had to be padded
>>> out to the minimum heap object alignment. At least it is harmless if
>>> ObjectAlignmentInBytes is not set, and if set it is only supported for
>>> 64-bit:
>>>
>>>    lp64_product(intx, ObjectAlignmentInBytes,
>>> 8,                             \
>>>            "Default object alignment in bytes, 8 is
>>> minimum")                \
>>>            range(8,
>>> 256)                                                     \
>>> constraint(ObjectAlignmentInBytesConstraintFunc,AtParse) \
>>>
>>> I'll get these cleaned up, but it sure would be nice if there was a way
>>> to reliably test it.
>>
>> I'd say that it's quite possible to test it!
>> Create a whitebox.cpp entry point for determining the size of a class.
> Ok, but I instead decided to use jcmd with "GC.class_stats KlassBytes"
>>
>> Run a java program calling the entry point and printing the
>> InstanceKlass size as computed by calling InstanceKlass::size() on a
>> set of pre-determined set of complex and simple classes (vtables,
>> itables, anonymous, etc.)
> For now I just did this from the command line to do some quick checking.
> No test written.
>> Have the java program wait after it's finished printing.
>>
>> Launch the SA agent and attach it to the process.
>> Through several layers of magic, execute the incantation:
>>
>> mgerdin at mgerdin03:~/work/repos/hg/jdk9/hs-rt-work/hotspot$
>> ../build/linux-x86_64-normal-server-slowdebug/images/jdk/bin/java
>> sun.jvm.hotspot.CLHSDB 6211
>> Attaching to process 6211, please wait...
>> hsdb> jseval
>> "sapkg.utilities.SystemDictionaryHelper.findInstanceKlass('java/lang/Object').getSize();"
>>
>> 472
> Ok. I did this to get sizes as SA sees them. They were not just wrong
> for existing JDK, but in most cases off by a large margin. I did some
> investigating.  This is InstanceKlass.getSize()
> 
>   public long getSize() {
>     return Oop.alignObjectSize(getHeaderSize() +
> Oop.alignObjectOffset(getVtableLen()) +
>                                Oop.alignObjectOffset(getItableLen()) +
> Oop.alignObjectOffset(getNonstaticOopMapSize()));
>   }
> 
> The problem is that getHeaderSize() returns the size in bytes, but the
> others all return the size in words. They need to be multiplied by the
> word size to get the right value since the caller of getSize() expects
> the result to be in bytes.
> 
> So we have multiple problems with SA with respect to the
> InstanceKlass.getSize() support:
> 
>  * Alignment issues introduced by me.
>  * Some minor other issues like using alignObjectSize when it's not
>    needed, and not taking into account extra fields for interfaces and
>    anonymous classes.
>  * Not multiplying the vtable, itable, and oopMapSize by the number of
>    bytes in a word.
>  * No test available.
> 
> I'm not too sure how to proceed here w.r.t. my CR. I'm inclined to just
> make the SA adjustments needed to take into consideration the alignment
> changes I've made to InstanceKlass, and file a CRs for the rest (one for
> the existing bugs and one for the lack of any test).
> 
> Please advise.
> 
> thanks,
> 
> Chris
> 
>>
>> You could also create a javascript source file in the test directory
>> which performs the appropriate calls and do
>> hsdb> jsload /path/to/file.js
>> hsdb> jseval "doit()"
>>
>> where
>> file.js:
>> doit = function() {
>>  sd = sapkg.utilities.SystemDictionaryHelper;
>>  do_klass = function(name) {
>>      writeln(sd.findInstanceKlass(name).getSize());
>>  }
>>
>>  do_klass('java/lang/Object');
>>  do_klass('java/lang/Class');
>> }
>>
>>
>> The only problem is that the test can't reliably execute on
>> unconfigured os x setups because of OS level security requirements for
>> attaching to processes.
>>
>> After detaching HSDB with the "quit" command you tell the debugged
>> java process to terminate, for example by printing some string on its
>> stdin.
>>
>> Easy, right? :)
>>
>> /Mikael
>>
>>>
>>> thanks,
>>>
>>> Chris
>>>
>>> On 12/8/15 1:54 AM, Mikael Gerdin wrote:
>>>> Hi Chris,
>>>>
>>>> Not a review but I'm fairly sure that you need to update the
>>>> serviceability agent to reflect these changes, see for example:
>>>>
>>>> public long getSize() {
>>>>   return Oop.alignObjectSize(
>>>> getHeaderSize() +
>>>> Oop.alignObjectOffset(getVtableLen()) +
>>>> Oop.alignObjectOffset(getItableLen()) +
>>>> Oop.alignObjectOffset(getNonstaticOopMapSize()));
>>>>   }
>>>>
>>>> in InstanceKlass.java
>>>>
>>>> /Mikael
>>>>
>>>> On 2015-12-04 23:02, Chris Plummer wrote:
>>>>> Hello,
>>>>>
>>>>> Please review the following:
>>>>>
>>>>> https://bugs.openjdk.java.net/browse/JDK-8143608
>>>>> http://cr.openjdk.java.net/~cjplummer/8143608/webrev.00/webrev.hotspot/
>>>>>
>>>>>
>>>>> A bit of background would help. The InstanceKlass object has a
>>>>> number of
>>>>> variable length fields that are laid out after the declared fields.
>>>>> When
>>>>> an InstanceKlass object is allocated, extra memory is allocated for it
>>>>> to leave room for these fields. The first three of these fields are
>>>>> vtable, itable, and nonstatic_oopmap. They are all arrays of HeapWord
>>>>> sized values, which means void* size, which means they only need
>>>>> 32-bit
>>>>> alignment on 32-bit systems. However, they have always been 64-bit
>>>>> aligned. This webrev removes the forced 64-bit alignment on 32-bit
>>>>> systems, saving footprint.
>>>>>
>>>>> This change affects all 32-bit platforms. It should have no net impact
>>>>> on 64-bit platforms since the fields remain (naturally) 64-bit aligned
>>>>> (unless of course I've introduced a bug). The intent is to not change
>>>>> what is done for 64-bit platforms.
>>>>>
>>>>> BTW, there is a change to AARCH64, which may seem odd at first. It
>>>>> just
>>>>> removes an "if" block where the condition should always have evaluated
>>>>> to false, so it should have no net affect.
>>>>>
>>>>> Tested with JPRT "-testset hotspot". Please let me know if you think
>>>>> there are any additional tests that should be run.
>>>>>
>>>>> thanks,
>>>>>
>>>>> Chris
>>>>>
>>>>
>>>
>>
> 


-- 
Dmitry Samersoff
Oracle Java development team, Saint Petersburg, Russia
* I would love to change the world, but they won't give me the source code.


More information about the serviceability-dev mailing list