Fix escape at store

This commit is contained in:
Quan Anh Mai 2025-12-29 21:43:47 +07:00
parent 5a34377d29
commit 06fb10fecf
2 changed files with 19 additions and 32 deletions

View File

@ -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

View File

@ -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();