diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_functools.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_functools.txt index 570dd3a68a..f0d8a8cb5e 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_functools.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_functools.txt @@ -36,8 +36,7 @@ test.test_functools.TestLRUC.test_lru_cache_threaded @ darwin-arm64,linux-aarch6 test.test_functools.TestLRUC.test_lru_cache_threaded2 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_functools.TestLRUC.test_lru_cache_threaded3 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_functools.TestLRUC.test_lru_cache_typed_is_not_recursive @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -# GR-71869 -!test.test_functools.TestLRUC.test_lru_cache_weakrefable @ darwin-arm64,linux-x86_64,win32-AMD64 +test.test_functools.TestLRUC.test_lru_cache_weakrefable @ darwin-arm64,linux-x86_64,win32-AMD64 test.test_functools.TestLRUC.test_lru_hash_only_once @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_functools.TestLRUC.test_lru_method @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_functools.TestLRUC.test_lru_no_args @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/superobject/SuperBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/superobject/SuperBuiltins.java index 20dd76af0a..d57d842d38 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/superobject/SuperBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/superobject/SuperBuiltins.java @@ -148,8 +148,8 @@ final Object executeCached(SuperObject self) { @Specialization(guards = {"isSingleContext()", "self == cachedSelf"}, assumptions = {"cachedSelf.getNeverReinitializedAssumption()"}, limit = "1") static Object cached(@NeverDefault @SuppressWarnings("unused") SuperObject self, - @SuppressWarnings("unused") @Cached("self") SuperObject cachedSelf, - @Cached(value = "self.getType()") Object type) { + @SuppressWarnings("unused") @Cached(value = "self", weak = true) SuperObject cachedSelf, + @Cached(value = "self.getType()", weak = true) Object type) { return type; } @@ -167,8 +167,8 @@ abstract static class GetObjectTypeNode extends PNodeWithContext { @Specialization(guards = {"isSingleContext()", "self == cachedSelf"}, assumptions = {"cachedSelf.getNeverReinitializedAssumption()"}, limit = "1") static Object cached(@NeverDefault @SuppressWarnings("unused") SuperObject self, - @SuppressWarnings("unused") @Cached("self") SuperObject cachedSelf, - @Cached(value = "self.getObjectType()") Object type) { + @SuppressWarnings("unused") @Cached(value = "self", weak = true) SuperObject cachedSelf, + @Cached(value = "self.getObjectType()", weak = true) Object type) { return type; } @@ -190,8 +190,8 @@ final Object executeCached(SuperObject self) { @Specialization(guards = {"isSingleContext()", "self == cachedSelf"}, assumptions = {"cachedSelf.getNeverReinitializedAssumption()"}, limit = "1") static Object cached(@NeverDefault @SuppressWarnings("unused") SuperObject self, - @SuppressWarnings("unused") @Cached("self") SuperObject cachedSelf, - @Cached(value = "self.getObject()") Object object) { + @SuppressWarnings("unused") @Cached(value = "self", weak = true) SuperObject cachedSelf, + @Cached(value = "self.getObject()", weak = true) Object object) { return object; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java index 1d7c79b34c..5f73173525 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java @@ -248,7 +248,7 @@ MroSequenceStorage.FinalAttributeAssumptionPair findAttrAndAssumptionInMRO(Objec assumptions = "cachedAttrInMROInfo.getAssumption()") static Object lookupConstantMROCached(Object klass, @Bind Node inliningTarget, - @Cached("klass") Object cachedKlass, + @Cached(value = "klass", weak = true) Object cachedKlass, @Cached IsSameTypeNode isSameTypeNode, @Cached("findAttrAndAssumptionInMRO(cachedKlass)") MroSequenceStorage.FinalAttributeAssumptionPair cachedAttrInMROInfo) { return cachedAttrInMROInfo.getValue(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromPythonObjectNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromPythonObjectNode.java index c3814700a6..4e71c58b60 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromPythonObjectNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromPythonObjectNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,6 +45,7 @@ import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; import com.oracle.graal.python.nodes.PNodeWithContext; +import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateUncached; @@ -99,7 +100,7 @@ protected static boolean isLongLivedObject(DynamicObject object) { @Idempotent protected static boolean isPrimitive(Object value) { - return value instanceof Integer || value instanceof Long || value instanceof Boolean || value instanceof Double; + return PythonUtils.isPrimitive(value); } @NonIdempotent diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/MroSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/MroSequenceStorage.java index 5d2e842e17..f162e20458 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/MroSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/MroSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -54,6 +54,7 @@ import com.oracle.truffle.api.dsl.NonIdempotent; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.utilities.CyclicAssumption; +import com.oracle.truffle.api.utilities.TruffleWeakReference; public final class MroSequenceStorage extends ArrayBasedSequenceStorage { @@ -71,7 +72,8 @@ public final class MroSequenceStorage extends ArrayBasedSequenceStorage { public static final class FinalAttributeAssumptionPair { @CompilationFinal private Assumption assumption; - @CompilationFinal private Object value; + @CompilationFinal private TruffleWeakReference value; + private Object valueStrongReference; public FinalAttributeAssumptionPair() { this.assumption = Truffle.getRuntime().createAssumption("attribute in MRO final"); @@ -87,11 +89,16 @@ public void invalidate() { @NonIdempotent public Object getValue() { - return value; + return value.get(); } public void setValue(Object value) { - this.value = value; + if (PythonUtils.isPrimitive(value)) { + // DynamicObjectStorage does not store the boxed object, but the raw primitive + // value, so we must protect the boxed object from GC ourselves + valueStrongReference = value; + } + this.value = new TruffleWeakReference<>(value); } @NonIdempotent diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java index 42a6d7c208..6515d828d1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java @@ -838,6 +838,10 @@ public static Object builtinClassToType(Object cls) { return cls; } + public static boolean isPrimitive(Object value) { + return value instanceof Integer || value instanceof Long || value instanceof Boolean || value instanceof Double; + } + public static final class NodeCounterWithLimit implements NodeVisitor { private int count; private final int limit; diff --git a/graalpython/lib-python/3/test/test_functools.py b/graalpython/lib-python/3/test/test_functools.py index fe4a58d371..d4443f3004 100644 --- a/graalpython/lib-python/3/test/test_functools.py +++ b/graalpython/lib-python/3/test/test_functools.py @@ -1872,7 +1872,7 @@ def test_staticmethod(x): del A del test_function - gc.collect() + support.gc_collect() for ref in refs: self.assertIsNone(ref())