On Tue, 5 Oct 2021 20:39:30 GMT, Leo Korinth <lkori...@openjdk.org> wrote:
>> The basic problem is that we are relying on undefined behaviour, as >> documented in the code: >> >> // This whole business of passing information from ResourceObj::operator new >> // to the ResourceObj constructor via fields in the "object" is technically >> UB. >> // But it seems to work within the limitations of HotSpot usage (such as no >> // multiple inheritance) with the compilers and compiler options we're using. >> // And it gives some possibly useful checking for misuse of ResourceObj. >> >> >> I am removing the undefined behaviour by passing the type of allocation >> through a thread local variable. >> >> This solution has some advantages: >> 1) it is not UB >> 2) it is simpler and easier to understand >> 3) it uses less memory (I could make it use even less if I made the enum >> `allocation_type` a u8) >> 4) in the *very* unlikely situation that stack memory (or embedded) already >> equals the data calculated from the address of the object, the code will >> also work. >> >> When doing the change, I also updated `allocated_on_stack()` to the new >> name `allocated_on_stack_or_embedded()` which is much harder to misinterpret. >> >> I also disallow to "fake" the memory type by explicitly calling >> `ResourceObj::set_allocation_type`. >> >> This forced me to change two places that is faking the allocation type of an >> embedded `GrowableArray` from `STACK_OR_EMBEDDED` to `C_HEAP`. The faking >> of the type is hard to understand as a `STACK_OR_EMBEDDED` `GrowableArray` >> can allocate any type of object. My guess is that `GrowableArray` has >> changed behaviour, or maybe that it was hard to understand because the old >> naming of `allocated_on_stack()`. >> >> I have also tried to update the comments. In doing that I not only changed >> the comments for this change, but also for the *incorrect* advice to always >> delete object you allocate with new. >> >> Testing on debug build tier1-3 >> Testing on release build tier1 > > Leo Korinth has updated the pull request incrementally with one additional > commit since the last revision: > > Use a thread local buffer so that the compiler might reorder operator new. Changes requested by kbarrett (Reviewer). src/hotspot/share/asm/codeBuffer.cpp line 143: > 141: NOT_PRODUCT(clear_strings()); > 142: > 143: assert(_default_oop_recorder.allocated_on_stack_or_embedded(), "should > be embedded object"); It might have been better to do this name change separately, to reduce distraction. src/hotspot/share/asm/codeBuffer.hpp line 369: > 367: // addresses in a sibling section. > 368: > 369: class CodeBuffer: public ResourceObj DEBUG_ONLY(COMMA private Scrubber) { Deriving from ResourceObj rather than the previous fakery seems good. I think the multiple-inheritance derivation from Scrubber could be removed, instead adding ~CodeBuffer to do the zapping. src/hotspot/share/asm/codeBuffer.hpp line 376: > 374: // CodeBuffers must be allocated on the stack except for a single > 375: // special case during expansion which is handled internally. This > 376: // is done to guarantee proper cleanup of resources. This comment seems dangling now that the associated operator definitions have been removed. src/hotspot/share/classfile/stackMapFrame.hpp line 66: > 64: > 65: StackMapFrame(const StackMapFrame& cp) : > 66: ResourceObj(), Good find. src/hotspot/share/gc/g1/g1Allocator.hpp line 243: > 241: _g1h(g1h), > 242: _allocation_region(NULL), > 243: _allocated_regions(2, mtGC), Good riddance. src/hotspot/share/memory/allocation.cpp line 154: > 152: > 153: #ifdef ASSERT > 154: thread_local ResourceObj::RecentAllocations > ResourceObj::_recent_allocations; Don't use `thread_local`. See the style guide. src/hotspot/share/memory/allocation.cpp line 234: > 232: } > 233: #endif // ASSERT > 234: Keep the blank line after the `#endif` src/hotspot/share/memory/allocation.hpp line 398: > 396: class ResourceObj ALLOCATION_SUPER_CLASS_SPEC { > 397: public: > 398: enum allocation_type : uint8_t { STACK_OR_EMBEDDED, RESOURCE_AREA, > C_HEAP, ARENA }; Consider adding an "empty" allocation-type, that indicates an entry in the RecentAllocations is unused. src/hotspot/share/memory/allocation.hpp line 414: > 412: // allocation is done in a recursive step. In that case an assert will > trigger. > 413: class RecentAllocations { > 414: static const unsigned BufferSize = 5; "5" seems like an odd choice. src/hotspot/share/memory/allocation.hpp line 416: > 414: static const unsigned BufferSize = 5; > 415: uintptr_t _begin[BufferSize]; > 416: uintptr_t _past_end[BufferSize]; I think these should be `const void*` rather than `uintptr_t`. src/hotspot/share/memory/memRegion.hpp line 110: > 108: // A ResourceObj version of MemRegionClosure > 109: > 110: class MemRegionClosureRO: public ResourceObj { I think this class could be deleted entirely, with the only derived class (`DirtyCardToOopClosure`) instead deriving from ResourceObj. src/hotspot/share/prims/jvmtiDeferredUpdates.hpp line 132: > 130: JvmtiDeferredUpdates() : > 131: _relock_count_after_wait(0), > 132: _deferred_locals_updates(1, mtCompiler) { } Good riddance. ------------- PR: https://git.openjdk.java.net/jdk/pull/5387