RFR(S): 8199698: Change 8199275 breaks template instantiation for xlC (and potentially other compliers)

coleen.phillimore at oracle.com coleen.phillimore at oracle.com
Fri Mar 16 14:10:00 UTC 2018

Hi, I've looked at both fixes and I really like Stefan's version. Having 
new and delete to be trivially inlined in allocation.hpp solves a lot of 
problems that I've found when removing more .inline.hpp includes from 
.hpp files (hashtable.inline.hpp from systemDictionary.hpp, I think).

Also, rather than NOINLINE, it's a lot nicer to put this in the .cpp file.


On 3/16/18 4:18 AM, Stefan Karlsson wrote:
> Hi Volker,
> This seems fine to be.
> An alternative fix for the allocation.inline.hpp problem would be to 
> move the AllocateHeap code into allocation.cpp, and get rid of the 
> NOINLINE usage.
> I've created a prototype for that:
> http://cr.openjdk.java.net/~stefank/8199698/prototypeAllocateHeapInCpp/
> I've visually inspected the output from NMT and it seems to give 
> correct stack traces. For example:
> [0x00007f4bffa10eff] ObjectSynchronizer::omAlloc(Thread*)+0x3cf
> [0x00007f4bffa1244c] ObjectSynchronizer::inflate(Thread*, oopDesc*, 
> ObjectSynchronizer::InflateCause)+0x8c
> [0x00007f4bffa1425a] ObjectSynchronizer::FastHashCode(Thread*, 
> oopDesc*)+0x7a
> [0x00007f4bff616142] JVM_IHashCode+0x52
>                              (malloc=4144KB type=Internal #129)
> Thanks,
> StefanK
> On 2018-03-15 18:20, Volker Simonis wrote:
>> Hi,
>> can I please have a review for the following small fix:
>> http://cr.openjdk.java.net/~simonis/webrevs/2018/8199698/
>> https://bugs.openjdk.java.net/browse/JDK-8199698
>> The fix is actually trivial: just defining the corresponding
>> "NOINLINE" macro for xlC. Unfortunately it's syntax requirements are a
>> little different for method declarations, compared to the other
>> platforms (it has to be placed AFTER the method declarator instead of
>> BEFORE it). Fortunately, there are no differences for method
>> definitions, so we can safely move the NOINLINE attributes from the
>> method declarations in allocation.hpp to the method definitions in
>> allocation.inline.hpp.
>> Thank you and best regards,
>> Volker
>> PS: or true C++ enthusiasts I've also included the whole story of why
>> this happens and why it happens just now, right after 8199275 :)
>> Change "8199275: Fix inclusions of allocation.inline.hpp" replaced the
>> inclusion of "allocation.inline.hpp" in some .hpp files (e.g.
>> constantPool.hpp) by "allocation.hpp".
>> "allocation.inline.hpp" contains not only the definition of some
>> inline methods (as the name implies) but also the definition of some
>> template methods (notably the various CHeapObj<>::operator new()
>> versions).
>> Template functions are on orthogonal concept with regard to inline
>> functions, but they share on implementation communality: at their call
>> sites, the compiler absolutely needs the corresponding function
>> definition. Otherwise it can either not inline the corresponding
>> function in the case of inline functions or it won't even be able to
>> create the corresponding instantiation in the case of a template
>> function.
>> Because of this reason, template functions and methods are defined in
>> their corresponding .inline.hpp files in HotSpot (even if they are not
>> subject to inlining). This is especially true for the before mentioned
>> CHeapObj<>:: new operators, which are explicitly marked as "NOINLINE"
>> in allocation.hpp but defined in allocation.inline.hpp.
>> Now every call site of these CHeapOb<>::new() operators which only
>> includes "allocation.hpp" will emit a call to the corresponding
>> instantiation of the CHeapObj<>:: new operator, but wont be able to
>> actually create that instantiation (simply because it doesn't see the
>> corresponding definition in allocation.inline.hpp). On the other side,
>> call sites of a CHeapObj<>:: new operator which include
>> allocation.inline.hpp will instantiate the required version in the
>> current compilation unit (or even inline that method instance if it is
>> not flagged as "NOINLINE").
>> If a compiler doesn't honor the "NOINLINE" attribute (or has an empty
>> definition for the NOINLIN macro like xlC), he can potentially inline
>> all the various template instances of CHeapObj<>:: new at all call
>> sites, if their implementation is available. This is exactly what has
>> happened on AIX/xlC before change 8199275 with the effect that the
>> resulting object files contained no single instance of the
>> corresponding new operators.
>> After change 8199275, the template definition of the CHeapObj<>:: new
>> operators aren't available any more at all call sites (because the
>> inclusion of allocation.inline.hpp was removed from some other .hpp
>> files which where included transitively before). As a result, the xlC
>> compiler will emit calls to the corresponding instantiations instead
>> of inlining them. But at all other call sites of the corresponding
>> operators, the operator instantiations are still inlined (because xlC
>> does not support "NOINLINE"), so we end up with link errors in
>> libjvm.so because of missing CHeapObj<>::new instances.
>>   As a general rule of thumb, we should always make template method
>> definitions available at all call sites, by placing them into
>> corresponding .inline.hpp files and including them appropriately.
>> Otherwise, we might end up without the required instantiations at link
>> time.
>> Unfortunately, there's no compile time check to enforce this
>> requirement. But we can misuse the "inline" keyword here, by
>> attributing template functions/methods as "inline". This way, the
>> compiler will warn us, if a template definition isn't available at a
>> specific call site. Of course this trick doesn't work if we
>> specifically want to define template functions/methods which shouldn't
>> be inlined, like in the current case :)

More information about the hotspot-dev mailing list