RFR: 8369238: Allow virtual thread preemption on some common class initialization paths [v6]

Coleen Phillimore coleenp at openjdk.org
Fri Oct 24 14:26:45 UTC 2025


On Thu, 23 Oct 2025 22:26:57 GMT, Patricio Chilano Mateo <pchilanomate at openjdk.org> wrote:

>> src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp line 73:
>> 
>>> 71:   bool update_map()    const { return false; }
>>> 72:   bool walk_cont()     const { return false; }
>>> 73:   bool include_argument_oops() const { return IncludeArgs; }
>> 
>> You made this a template rather than having an _include_argument_oops property for performance?
>
> Not really, using a bool member would work too.

ok, good to know.  We could or might not change it in the follow-up issue to move SmallRegisterMap to common code.

>> src/hotspot/share/runtime/continuationFreezeThaw.cpp line 1123:
>> 
>>> 1121:       assert(!call.is_valid() || call.is_invokestatic(), "only invokestatic allowed");
>>> 1122:       if (call.is_invokestatic() && call.size_of_parameters() > 0) {
>>> 1123:         assert(top_frame.interpreter_frame_expression_stack_size() > 0, "should have parameters in exp stack");
>> 
>> The "this" pointer will be on the top of the interpreter frame expression stack right?  Are size of parameters ever 0 here then?
>
> This is only for `invokestatic` so no this pointer.

I see, this just verifies if size_of_parameters > 0, there must be something on the expression stack.

>> src/hotspot/share/runtime/continuationFreezeThaw.cpp line 1653:
>> 
>>> 1651:   }
>>> 1652:   inline intptr_t* anchor_mark_set_pd();
>>> 1653:   inline void anchor_mark_clear_pd();
>> 
>> The code is really confused whether "pd" is the beginning of the method name or the end.  Both are used but mostly in the beginning of the method. The freeze/thaw code uses it at the end so this is okay.
>
> I added `patch_pd_unused` in 8359222 which should have been `patch_unused_pd`. :)

I like AnchorMark.  There are other places that clear_anchor in this code.  Can they use AnchorMark?

>> src/hotspot/share/runtime/continuationFreezeThaw.cpp line 1731:
>> 
>>> 1729:   int bci;
>>> 1730:   if (preempt_kind == Continuation::monitorenter) {
>>> 1731:     assert(top.is_interpreted_frame() || top.is_runtime_frame(), "");
>> 
>> So could you use precond() here since it's a precondition and you have no assert message?
>
> Yes, but don’t really see the benefit. It’s replacing a null string for `precond` in a crash.

These null strings make me wish we had an assert with no strings if one isn't provided.  I suppose the "precond" string isn't much better. I don't like null strings - it seems like you want to say why you're asserting this condition or what it means, ie take the opportunity to provide a bit more documentation.  Like here you could say that monitorenter is only preempted when the top frame is interpreted or runtime (which is coming from the compiler right?), which I suppose is redundant with the condition.  I suppose nothing is better than "sanity" or "should be".  I retract my suggestion to use precond though.  Others might believe it's better but I'm agnostic.

>> src/hotspot/share/runtime/continuationFreezeThaw.cpp line 2686:
>> 
>>> 2684: 
>>> 2685:   {
>>> 2686:     HandleMarkCleaner hmc(current);  // Cleanup so._conth Handle
>> 
>> Why doesn't a plain HandleMark do this?
>> I think you chose HandleMarkCleaner because this is going to back to the interpreter code, so to be like JRT_ENTRY code.
>> So add something like before going back to the interpreted Java code.
>
> A full `HandleMark` works too. It’s just that there is already a `HandleMark` in the callstack (from the original upcall to Java from the carrier thread), so we can use a `HandleMarkCleaner` here.

The main place we have HandleMarkCleaners are in the JRT_ENTRY.  Can you change the comment to:
// Returning to java so cleanup all handles including so._conth Handle

or something like that.

>> src/hotspot/share/runtime/javaThread.hpp line 1372:
>> 
>>> 1370: };
>>> 1371: 
>>> 1372: class PreemptableInitCall {
>> 
>> If this is only used in instanceKlass.cpp, I think the definition should be there and not in javaThread.hpp.  It's not using private methds in javaThread.hpp as far as I can tell.
>
> Moved, and also `ThreadWaitingForClassInit`. Should I move pre-existent `ThreadInClassInitializer` too?

It's preexisting so I don't think so.  Leave it for a trivial change.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2460563120
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2460632055
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2460637514
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2460668197
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2460687828
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2460751847


More information about the hotspot-dev mailing list