JDK-8225652 : frame::patch_pc sets _pc and _deopt_state incorrectly during deoptimization
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 13
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: x86
  • Submitted: 2019-06-12
  • Updated: 2024-02-20
  • Resolved: 2023-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 19
19Resolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
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.
Comments
[~pchilanomate] Apologies for not noting that the duplicates link had been removed.
16-02-2024

> [~alanb] Any particular reason you removed the duplicates link? I didn't touch this issue directly but was fixing up some links from JDK-8284161, maybe something got messed up, I'll check.
16-02-2024

[~alanb] Any particular reason you removed the duplicates link?
15-02-2024

[~pchilanomate] Please link it as a duplicate as well.
15-02-2024

Closing as duplicate of JDK-8284161 which already addressed this issue.
08-03-2023

Only bugs associated with a changeset should be closed as "Fixed". This bug should probably be closed as a duplicate of JDK-8284161.
08-03-2023

This has already been resolved in 8284161, and the subsequent port related changes I linked.
07-03-2023

ILW = MLM = P4
18-06-2019