JDK 19 |
---|
19Resolved |
Duplicate :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
The frame::patch_pc method is used for deoptimization and does three things: 1. patches the frame’s callee’s return address on the stack, 2. sets the frame object's _pc, and 3. sets the frame object's _deopt_state. The methods does one of these things correctly. This bug is currently benign because it is called with a deoptimization entry pc only in frame::deoptimize, which, in turn, is called only from Deoptimization::deoptimize_single_frame, which passes it a local frame object (by-value argument) that is immediately discarded after the call. The issue has been discovered in Project Loom, where continuation code calls frame::deoptimize, and the frame object is subsequently queried. The method branches to the is_deoptimized/not_deoptimized cases based on whether CompiledMethod::get_deopt_original_pc(this) returns NULL. However, when called from frame::patch_pc, NULL is *always* returned because CompiledMethod::get_deopt_original_pc only returns a non-NULL value if the _pc field of the frame is set to a deoptimization entry, but frame::patch_pc doesn't set the _pc field appropriately before calling get_deopt_original_pc. Running tests in tiers 1-3 with guarantee(false, "") in the is_deoptimized branch of patch_pc confirms that this branch is never taken. As a result, _deopt_state is always set to false, and _pc is incorrectly set to the deopt entry, in violation of an invariant that a frame object’s pc should always point to the "idealized" pc. Adding either of the following two assertions (that should be true) to the end of the method immediately fails in tier1: assert (!is_compiled_frame() || !_cb->as_compiled_method()->is_deopt_entry(_pc), "must be idealized pc“); frame f(this->sp(), this->unextended_sp(), this->fp(), pc); assert(f.is_deoptimized_frame() == this->is_deoptimized_frame() && f.pc() == this->pc() && f.raw_pc() == this->raw_pc(), "must be"); This means that subsequent calls to frame::is_deoptimized_frame() and frame::pc() (that’s supposed to return the idealized pc) return incorrect results. Again, this is currently benign because the JDK discards the incorrect frame object whenever the is_deoptimized branch is supposed to have been taken. The frame class constructors do correctly set _pc and _deopt_state, as they call CompiledMethod::get_deopt_original_pc after setting _pc, and then possibly set it again if it returns a non-NULL value. A proposed fix that does the same (and contains the assertions above) is attached as a patch and has passed tiers 1-3.
|