From 06fb10fecf1ee373a6e13f572523100ee75fa87e Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Mon, 29 Dec 2025 21:43:47 +0700 Subject: [PATCH] Fix escape at store --- src/hotspot/share/opto/memnode.cpp | 43 +++++++------------ .../escapeAnalysis/TestLoadFolding.java | 8 ++-- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 977cf6f3b74..93455038d74 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1506,34 +1506,21 @@ MemNode::LocalEA::EscapeStatus MemNode::LocalEA::check_escape_status(Node* ctl) } else if (out->is_Mem()) { // A Store or a LoadStore if (n == out->in(MemNode::ValueIn)) { - Node* ptr = out->in(MemNode::Address); - if (ptr->is_AddP()) { - Node* ptr_base = ptr->as_AddP()->base_node(); - if (!_phase->type(ptr_base)->isa_oopptr()) { - // Maybe a store to raw memory - res = ESCAPED; - break; - } - - // If an object o is stored into a field of a holder h and h has not escaped, we can - // say that o has not escaped, too - LocalEA store_base_ea(_phase, ptr->as_AddP()->base_node()); - if (!store_base_ea.is_candidate()) { - res = ESCAPED; - break; - } - - // This is similar to store_base_ea.check_escape_status(ctl), the differences are that - // it avoids the drawbacks of recursion and does not unnecessarily collect - // _not_escaped_controls again - for (uint i = 0; i < store_base_ea.aliases().size(); i++) { - dependencies.push(store_base_ea.aliases().at(i)); - } - } else { - // Do not know into where n is stored, give up - res = ESCAPED; - break; - } + // You may wonder if we can reason about the escape status of the destination memory + // here so that we can determine that an object has not escaped if the object into which + // it is stored has not escaped. Unfortunately, this store breaks _aliases, because there + // is now a memory that can alias the object we are analyzed, and a load from such memory + // is not visited by this analysis. For example: + // Object o = new Object; + // Holder h = new Holder; + // h.o = o; + // do_something(); + // Object p = h.o; + // escape(p); + // Then, o escapes at escape(p), but we will not visit that. In order for this to work, + // the constructor needs to be more conservative when it collects _aliases. + res = ESCAPED; + break; } else if (n == out->in(MemNode::Address) && (!out->is_Store() || out->as_Store()->is_mismatched_access())) { // Mismatched accesses can lie in a different alias class and are protected by memory // barriers, so we cannot be aggressive and walk past memory barriers if there is a diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestLoadFolding.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestLoadFolding.java index 4b2076e9756..0cf0ebfb623 100644 --- a/test/hotspot/jtreg/compiler/escapeAnalysis/TestLoadFolding.java +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestLoadFolding.java @@ -241,7 +241,7 @@ public class TestLoadFolding { } @Test - @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, failOn = IRNode.LOAD_I, counts = {IRNode.ALLOC, "1"}) + @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, counts = {IRNode.ALLOC, "1"}) public int test112() { // The object has been stored into memory but the destination does not escape PointHolder h = new PointHolder(); @@ -254,7 +254,7 @@ public class TestLoadFolding { } @Test - @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, failOn = IRNode.LOAD_I, counts = {IRNode.ALLOC, "2"}) + @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, counts = {IRNode.ALLOC, "2"}) public int test113() { // The object has been stored into memory but the destination has not escaped PointHolder h = new PointHolder(); @@ -267,7 +267,7 @@ public class TestLoadFolding { } @Test - @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, failOn = IRNode.LOAD_I, counts = {IRNode.ALLOC, "3"}) + @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, counts = {IRNode.ALLOC, "3"}) public int test114(boolean b) { // A Phi has been stored into memory but the destination has not escaped PointHolder h = new PointHolder(); @@ -281,7 +281,7 @@ public class TestLoadFolding { } @Test - @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, failOn = IRNode.LOAD_I, counts = {IRNode.ALLOC, "3"}) + @IR(applyIf = {"DoLocalEscapeAnalysis", "true"}, counts = {IRNode.ALLOC, "3"}) public int test115(boolean b) { // The object has been stored into a Phi but the destination has not escaped PointHolder h1 = new PointHolder();