From a28a2bc108c178187fdb29854fcf4e5d92b12623 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 16 Sep 2026 09:25:28 +0200 Subject: [PATCH 1/5] Move builtin type flags into PythonBuiltinClassType --- .../src/tests/test_type.py | 17 ++ .../src/tests/unittest_tags/test_typing.txt | 2 + .../builtins/PythonBuiltinClassType.java | 262 ++++++++++++------ .../builtins/objects/type/TypeNodes.java | 156 +---------- 4 files changed, 190 insertions(+), 247 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_type.py b/graalpython/com.oracle.graal.python.test/src/tests/test_type.py index 1645c6b831..b00094268e 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_type.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_type.py @@ -214,12 +214,19 @@ def __new__(cls, x, y): @skipIf(sys.implementation.name == 'cpython' and sys.version_info[0:2] < (3, 8), "skipping for cPython versions < 3.8") def test_flags(): import functools + import typing def testfunction(self): """some doc""" return self + TPFLAGS_SEQUENCE = 1 << 5 + TPFLAGS_MAPPING = 1 << 6 + TPFLAGS_HEAPTYPE = 1 << 9 + TPFLAGS_BASETYPE = 1 << 10 + TPFLAGS_HAVE_GC = 1 << 14 TPFLAGS_METHOD_DESCRIPTOR = 1 << 17 + TPFLAGS_MATCH_SELF = 1 << 22 TPFLAGS_LONG_SUBCLASS = 1 << 24 TPFLAGS_LIST_SUBCLASS = 1 << 25 TPFLAGS_TUPLE_SUBCLASS = 1 << 26 @@ -231,6 +238,16 @@ def testfunction(self): cached = functools.lru_cache(1)(testfunction) + assert typing.Generic.__flags__ & TPFLAGS_HEAPTYPE + assert object.__flags__ & TPFLAGS_BASETYPE + assert type.__flags__ & TPFLAGS_HAVE_GC + assert list.__flags__ & TPFLAGS_SEQUENCE + assert list.__flags__ & TPFLAGS_MATCH_SELF + assert dict.__flags__ & TPFLAGS_MAPPING + assert BaseException.__flags__ & TPFLAGS_BASE_EXC_SUBCLASS + assert ValueError.__flags__ & TPFLAGS_BASE_EXC_SUBCLASS + assert ValueError.__flags__ & TPFLAGS_HAVE_GC + assert type.__flags__ & TPFLAGS_TYPE_SUBCLASS assert not type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, "masked __flags__ = {}, expected {}".format(type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, 0) assert type(list.append).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, "masked __flags__ = {}, expected {}".format(type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, TPFLAGS_METHOD_DESCRIPTOR) assert type(list.__add__).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, "masked __flags__ = {}, expected {}".format(type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, TPFLAGS_METHOD_DESCRIPTOR) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_typing.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_typing.txt index 0812916447..4549645ae7 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_typing.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_typing.txt @@ -243,6 +243,7 @@ test.test_typing.GenericTests.test_pep_695_generic_function_with_future_annotati test.test_typing.GenericTests.test_pep_695_generic_method_with_future_annotations @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.GenericTests.test_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.GenericTests.test_pep_695_generics_with_future_annotations_nested_in_function @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_typing.GenericTests.test_pickle @ linux-x86_64 test.test_typing.GenericTests.test_repr @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.GenericTests.test_repr_2 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.GenericTests.test_repr_3 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github @@ -452,6 +453,7 @@ test.test_typing.ProtocolTests.test_protocols_isinstance_properties_and_descript test.test_typing.ProtocolTests.test_protocols_isinstance_py36 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.ProtocolTests.test_protocols_issubclass @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.ProtocolTests.test_protocols_issubclass_non_callable @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_typing.ProtocolTests.test_protocols_pickleable @ linux-x86_64 test.test_typing.ProtocolTests.test_protocols_support_register @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.ProtocolTests.test_reversible @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_typing.ProtocolTests.test_runtime_checkable_generic @ 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/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index 95fdc70b30..0637f0eea0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -283,6 +283,7 @@ import com.oracle.graal.python.builtins.objects.tuple.TupleGetterBuiltins; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TypeBuiltins; +import com.oracle.graal.python.builtins.objects.type.TypeFlags; import com.oracle.graal.python.builtins.objects.types.GenericAliasBuiltins; import com.oracle.graal.python.builtins.objects.types.GenericAliasIteratorBuiltins; import com.oracle.graal.python.builtins.objects.types.UnionTypeBuiltins; @@ -319,32 +320,32 @@ public enum PythonBuiltinClassType implements TruffleObject { When called, it accepts no arguments and returns a new featureless instance that has no instance attributes and cannot be given any. """)), - PythonClass("type", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().addDict(264).slots(TypeBuiltins.SLOTS).doc(""" + PythonClass("type", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().typeSubclass().addDict(264).slots(TypeBuiltins.SLOTS).doc(""" type(object) -> the object's type type(name, bases, dict, **kwds) -> a new type""")), - PArray("array", PythonObject, newBuilder().publishInModule("array").basetype().slots(ArrayBuiltins.SLOTS)), - PArrayIterator("arrayiterator", PythonObject, newBuilder().disallowInstantiation().slots(IteratorBuiltins.SLOTS)), - PIterator("iterator", PythonObject, newBuilder().disallowInstantiation().slots(IteratorBuiltins.SLOTS)), + PArray("array", PythonObject, newBuilder().publishInModule("array").basetype().sequence().slots(ArrayBuiltins.SLOTS)), + PArrayIterator("arrayiterator", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(IteratorBuiltins.SLOTS)), + PIterator("iterator", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(IteratorBuiltins.SLOTS)), /** See {@link com.oracle.graal.python.builtins.objects.function.PBuiltinFunction} */ - PBuiltinFunction("method_descriptor", PythonObject, newBuilder().disallowInstantiation().slots(AbstractFunctionBuiltins.SLOTS, MethodDescriptorBuiltins.SLOTS)), + PBuiltinFunction("method_descriptor", PythonObject, newBuilder().haveGC().methodDescriptor().disallowInstantiation().slots(AbstractFunctionBuiltins.SLOTS, MethodDescriptorBuiltins.SLOTS)), /** See {@link com.oracle.graal.python.builtins.objects.method.PBuiltinMethod} */ PBuiltinFunctionOrMethod( "builtin_function_or_method", PythonObject, - newBuilder().disallowInstantiation().slots(AbstractMethodBuiltins.SLOTS, BuiltinFunctionOrMethodBuiltins.SLOTS)), + newBuilder().haveGC().disallowInstantiation().slots(AbstractMethodBuiltins.SLOTS, BuiltinFunctionOrMethodBuiltins.SLOTS)), /** See {@link com.oracle.graal.python.builtins.objects.function.PBuiltinFunction} */ - WrapperDescriptor(J_WRAPPER_DESCRIPTOR, PythonObject, newBuilder().disallowInstantiation().slots(AbstractFunctionBuiltins.SLOTS, WrapperDescriptorBuiltins.SLOTS)), + WrapperDescriptor(J_WRAPPER_DESCRIPTOR, PythonObject, newBuilder().haveGC().methodDescriptor().disallowInstantiation().slots(AbstractFunctionBuiltins.SLOTS, WrapperDescriptorBuiltins.SLOTS)), /** See {@link com.oracle.graal.python.builtins.objects.method.PBuiltinMethod} */ - MethodWrapper("method-wrapper", PythonObject, newBuilder().slots(AbstractMethodBuiltins.SLOTS, MethodWrapperBuiltins.SLOTS)), + MethodWrapper("method-wrapper", PythonObject, newBuilder().haveGC().slots(AbstractMethodBuiltins.SLOTS, MethodWrapperBuiltins.SLOTS)), /** See {@link com.oracle.graal.python.builtins.objects.method.PBuiltinMethod} */ - PBuiltinMethod("builtin_method", PBuiltinFunctionOrMethod, newBuilder()), + PBuiltinMethod("builtin_method", PBuiltinFunctionOrMethod, newBuilder().haveGC()), PBuiltinClassMethod("classmethod_descriptor", PythonObject, newBuilder().slots(ClassmethodCommonBuiltins.SLOTS, BuiltinClassmethodBuiltins.SLOTS)), - GetSetDescriptor("getset_descriptor", PythonObject, newBuilder().disallowInstantiation().slots(GetSetDescriptorTypeBuiltins.SLOTS)), - MemberDescriptor(J_MEMBER_DESCRIPTOR, PythonObject, newBuilder().disallowInstantiation().slots(MemberDescriptorBuiltins.SLOTS)), + GetSetDescriptor("getset_descriptor", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(GetSetDescriptorTypeBuiltins.SLOTS)), + MemberDescriptor(J_MEMBER_DESCRIPTOR, PythonObject, newBuilder().haveGC().disallowInstantiation().slots(MemberDescriptorBuiltins.SLOTS)), PByteArray( "bytearray", PythonObject, - newBuilder().publishInModule(J_BUILTINS).basetype().slots(BytesCommonBuiltins.SLOTS, ByteArrayBuiltins.SLOTS).doc(""" + newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().slots(BytesCommonBuiltins.SLOTS, ByteArrayBuiltins.SLOTS).doc(""" bytearray(iterable_of_ints) -> bytearray bytearray(string, encoding[, errors]) -> bytearray bytearray(bytes_or_buffer) -> mutable copy of bytes_or_buffer @@ -357,7 +358,7 @@ public enum PythonBuiltinClassType implements TruffleObject { - a bytes or a buffer object - any object implementing the buffer API. - an integer""")), - PBytes("bytes", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(BytesCommonBuiltins.SLOTS, BytesBuiltins.SLOTS).doc(""" + PBytes("bytes", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().bytesSubclass().slots(BytesCommonBuiltins.SLOTS, BytesBuiltins.SLOTS).doc(""" bytes(iterable_of_ints) -> bytes bytes(string, encoding[, errors]) -> bytes bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer @@ -369,8 +370,8 @@ public enum PythonBuiltinClassType implements TruffleObject { - a text string encoded using the specified encoding - any object implementing the buffer API. - an integer""")), - PCell("cell", PythonObject, newBuilder().slots(CellBuiltins.SLOTS)), - PSimpleNamespace("SimpleNamespace", PythonObject, newBuilder().publishInModule("types").basetype().addDict(16).slots(SimpleNamespaceBuiltins.SLOTS).doc(""" + PCell("cell", PythonObject, newBuilder().haveGC().slots(CellBuiltins.SLOTS)), + PSimpleNamespace("SimpleNamespace", PythonObject, newBuilder().publishInModule("types").basetype().haveGC().addDict(16).slots(SimpleNamespaceBuiltins.SLOTS).doc(""" A simple attribute-based namespace. SimpleNamespace(mapping_or_iterable=(), /, **kwargs)""")), @@ -379,31 +380,34 @@ public enum PythonBuiltinClassType implements TruffleObject { partial(func, *args, **keywords) - new function with partial application of the given arguments and keywords. """)), - PLruListElem("_lru_list_elem", PythonObject, newBuilder().publishInModule("functools").disallowInstantiation()), - PLruCacheWrapper(J_LRU_CACHE_WRAPPER, PythonObject, newBuilder().moduleName("functools").publishInModule("_functools").basetype().addDict().slots(LruCacheWrapperBuiltins.SLOTS).doc(""" - Create a cached callable that wraps another function. + PLruListElem("_lru_list_elem", PythonObject, newBuilder().publishInModule("functools").haveGC().disallowInstantiation()), + PLruCacheWrapper( + J_LRU_CACHE_WRAPPER, + PythonObject, + newBuilder().moduleName("functools").publishInModule("_functools").basetype().haveGC().methodDescriptor().addDict().slots(LruCacheWrapperBuiltins.SLOTS).doc(""" + Create a cached callable that wraps another function. - user_function: the function being cached + user_function: the function being cached - maxsize: 0 for no caching - None for unlimited cache size - n for a bounded cache + maxsize: 0 for no caching + None for unlimited cache size + n for a bounded cache - typed: False cache f(3) and f(3.0) as identical calls - True cache f(3) and f(3.0) as distinct calls + typed: False cache f(3) and f(3.0) as identical calls + True cache f(3) and f(3.0) as distinct calls - cache_info_type: namedtuple class with the fields: - hits misses currsize maxsize - """)), - PDeque(J_DEQUE, PythonObject, newBuilder().publishInModule("_collections").moduleName("collections").basetype().slots(DequeBuiltins.SLOTS)), + cache_info_type: namedtuple class with the fields: + hits misses currsize maxsize + """)), + PDeque(J_DEQUE, PythonObject, newBuilder().publishInModule("_collections").moduleName("collections").basetype().haveGC().slots(DequeBuiltins.SLOTS)), PTupleGetter(J_TUPLE_GETTER, PythonObject, newBuilder().publishInModule("_collections").basetype().slots(TupleGetterBuiltins.SLOTS)), - PDequeIter(J_DEQUE_ITER, PythonObject, newBuilder().publishInModule("_collections").slots(DequeIterCommonBuiltins.SLOTS, DequeIterBuiltins.SLOTS)), - PDequeRevIter(J_DEQUE_REV_ITER, PythonObject, newBuilder().publishInModule("_collections").slots(DequeIterCommonBuiltins.SLOTS, DequeRevIterBuiltins.SLOTS)), + PDequeIter(J_DEQUE_ITER, PythonObject, newBuilder().publishInModule("_collections").haveGC().slots(DequeIterCommonBuiltins.SLOTS, DequeIterBuiltins.SLOTS)), + PDequeRevIter(J_DEQUE_REV_ITER, PythonObject, newBuilder().publishInModule("_collections").haveGC().slots(DequeIterCommonBuiltins.SLOTS, DequeRevIterBuiltins.SLOTS)), PComplex("complex", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(ComplexBuiltins.SLOTS).doc(""" Create a complex number from a real part and an optional imaginary part. This is equivalent to (real + imag*1j) where imag defaults to 0.""")), - PDict("dict", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(DictBuiltins.SLOTS, DictReprBuiltin.SLOTS).doc(""" + PDict("dict", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().mapping().dictSubclass().slots(DictBuiltins.SLOTS, DictReprBuiltin.SLOTS).doc(""" dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs @@ -413,8 +417,8 @@ This is equivalent to (real + imag*1j) where imag defaults to 0.""")), d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)""")), - PDefaultDict(J_DEFAULTDICT, PDict, newBuilder().moduleName("collections").publishInModule("_collections").basetype().slots(DefaultDictBuiltins.SLOTS)), - POrderedDict(J_ORDERED_DICT, PDict, newBuilder().publishInModule("_collections").basetype().addDict(96).slots(OrderedDictBuiltins.SLOTS)), + PDefaultDict(J_DEFAULTDICT, PDict, newBuilder().moduleName("collections").publishInModule("_collections").basetype().haveGC().mapping().slots(DefaultDictBuiltins.SLOTS)), + POrderedDict(J_ORDERED_DICT, PDict, newBuilder().publishInModule("_collections").basetype().haveGC().addDict(96).slots(OrderedDictBuiltins.SLOTS)), PDictItemIterator(J_DICT_ITEMITERATOR, PythonObject, newBuilder().disallowInstantiation().slots(IteratorBuiltins.SLOTS)), PDictReverseItemIterator(J_DICT_REVERSE_ITEMITERATOR, PythonObject, newBuilder().slots(IteratorBuiltins.SLOTS)), PDictItemsView(J_DICT_ITEMS, PythonObject, newBuilder().disallowInstantiation().slots(DictViewBuiltins.SLOTS, DictReprBuiltin.SLOTS)), @@ -429,7 +433,7 @@ This is equivalent to (real + imag*1j) where imag defaults to 0.""")), POrderedDictItems("odict_items", PDictItemsView, newBuilder().slots(OrderedDictItemsBuiltins.SLOTS)), POrderedDictIterator("odict_iterator", PythonObject, newBuilder().slots(OrderedDictIteratorBuiltins.SLOTS)), PEllipsis("ellipsis", PythonObject, newBuilder().slots(EllipsisBuiltins.SLOTS)), - PEnumerate("enumerate", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(EnumerateBuiltins.SLOTS).doc(""" + PEnumerate("enumerate", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(EnumerateBuiltins.SLOTS).doc(""" Return an enumerate object. iterable @@ -440,7 +444,7 @@ The enumerate object yields pairs containing a count (from start, which enumerate is useful for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ...""")), - PMap("map", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(MapBuiltins.SLOTS).doc(""" + PMap("map", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(MapBuiltins.SLOTS).doc(""" map(func, *iterables) --> map object Make an iterator that computes the function using arguments from @@ -454,25 +458,25 @@ Return an iterator yielding those items of iterable for which function(item) PFloat( "float", PythonObject, - newBuilder().publishInModule(J_BUILTINS).basetype().slots(FloatBuiltins.SLOTS).doc(""" + newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().slots(FloatBuiltins.SLOTS).doc(""" Convert a string or number to a floating point number, if possible.""")), - PFrame("frame", PythonObject, newBuilder().disallowInstantiation().slots(FrameBuiltins.SLOTS)), + PFrame("frame", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(FrameBuiltins.SLOTS)), PFrameLocalsProxy("FrameLocalsProxy", PythonObject, newBuilder().disallowInstantiation().slots(FrameLocalsProxyBuiltins.SLOTS)), PFrozenSet( "frozenset", PythonObject, - newBuilder().publishInModule(J_BUILTINS).basetype().slots(BaseSetBuiltins.SLOTS, FrozenSetBuiltins.SLOTS).doc(""" + newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().slots(BaseSetBuiltins.SLOTS, FrozenSetBuiltins.SLOTS).doc(""" frozenset() -> empty frozenset object frozenset(iterable) -> frozenset object Build an immutable unordered collection of unique elements.""")), - PFunction("function", PythonObject, newBuilder().addDict().slots(AbstractFunctionBuiltins.SLOTS, FunctionBuiltins.SLOTS)), - PGenerator("generator", PythonObject, newBuilder().disallowInstantiation().slots(GeneratorBuiltins.SLOTS)), + PFunction("function", PythonObject, newBuilder().haveGC().methodDescriptor().addDict().slots(AbstractFunctionBuiltins.SLOTS, FunctionBuiltins.SLOTS)), + PGenerator("generator", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(GeneratorBuiltins.SLOTS)), PCoroutine("coroutine", PythonObject, newBuilder().slots(CoroutineBuiltins.SLOTS)), PCoroutineWrapper("coroutine_wrapper", PythonObject, newBuilder().slots(CoroutineWrapperBuiltins.SLOTS)), - PAsyncGenerator("async_generator", PythonObject, newBuilder().slots(AsyncGeneratorBuiltins.SLOTS)), + PAsyncGenerator("async_generator", PythonObject, newBuilder().haveGC().slots(AsyncGeneratorBuiltins.SLOTS)), PAnextAwaitable("anext_awaitable", PythonObject, newBuilder().slots(ANextAwaitableBuiltins.SLOTS)), - PInt("int", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(IntBuiltins.SLOTS).doc(""" + PInt("int", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().longSubclass().slots(IntBuiltins.SLOTS).doc(""" int([x]) -> integer int(x, base=10) -> integer @@ -485,28 +489,28 @@ Return an iterator yielding those items of iterable for which function(item) given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.""")), - Boolean("bool", PInt, newBuilder().publishInModule(J_BUILTINS).slots(BoolBuiltins.SLOTS).doc(""" + Boolean("bool", PInt, newBuilder().publishInModule(J_BUILTINS).matchSelf().slots(BoolBuiltins.SLOTS).doc(""" bool(x) -> bool Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.""")), - PList("list", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(ListBuiltins.SLOTS).doc(""" + PList("list", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().sequence().listSubclass().slots(ListBuiltins.SLOTS).doc(""" Built-in mutable sequence. If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.""")), - PMappingproxy("mappingproxy", PythonObject, newBuilder().slots(MappingproxyBuiltins.SLOTS)), + PMappingproxy("mappingproxy", PythonObject, newBuilder().haveGC().mapping().slots(MappingproxyBuiltins.SLOTS)), PMemoryView( "memoryview", PythonObject, - newBuilder().publishInModule(J_BUILTINS).slots(MemoryViewBuiltins.SLOTS).doc(""" + newBuilder().publishInModule(J_BUILTINS).haveGC().sequence().slots(MemoryViewBuiltins.SLOTS).doc(""" Create a new memoryview object which references the given object.""")), PMemoryViewIterator("memory_iterator", PythonObject, newBuilder().slots(MemoryViewIteratorBuiltins.SLOTS)), PAsyncGenASend("async_generator_asend", PythonObject, newBuilder().slots(AsyncGenSendBuiltins.SLOTS)), PAsyncGenAThrow("async_generator_athrow", PythonObject, newBuilder().slots(AsyncGenThrowBuiltins.SLOTS)), PAsyncGenAWrappedValue("async_generator_wrapped_value", PythonObject, newBuilder()), - PMethod("method", PythonObject, newBuilder().slots(AbstractMethodBuiltins.SLOTS, MethodBuiltins.SLOTS).doc(""" + PMethod("method", PythonObject, newBuilder().haveGC().slots(AbstractMethodBuiltins.SLOTS, MethodBuiltins.SLOTS).doc(""" Create a bound instance method object.""")), PMMap("mmap", PythonObject, newBuilder().publishInModule("mmap").basetype().slots(MMapBuiltins.SLOTS).doc(""" Windows: mmap(fileno, length[, tagname[, access[, offset]]]) @@ -522,7 +526,7 @@ false, fileno is not duplicated and size() and resize() are unavailable. To map anonymous memory, pass -1 as fileno.""")), PNone("NoneType", PythonObject, newBuilder().slots(NoneBuiltins.SLOTS)), PNotImplemented("NotImplementedType", PythonObject, newBuilder().slots(NotImplementedBuiltins.SLOTS)), - PProperty(J_PROPERTY, PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(PropertyBuiltins.SLOTS).doc(""" + PProperty(J_PROPERTY, PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(PropertyBuiltins.SLOTS).doc(""" Property attribute. fget @@ -558,14 +562,14 @@ def x(self): PSimpleQueue( J_SIMPLE_QUEUE, PythonObject, - newBuilder().publishInModule("_queue").basetype().slots(SimpleQueueBuiltins.SLOTS).doc(""" + newBuilder().publishInModule("_queue").basetype().haveGC().slots(SimpleQueueBuiltins.SLOTS).doc(""" SimpleQueue() -- Simple, unbounded, reentrant FIFO queue.""")), - PPoll("poll", PythonObject, newBuilder().moduleName("select").disallowInstantiation()), + PPoll("poll", PythonObject, newBuilder().moduleName("select").haveGC().disallowInstantiation()), PRandom("Random", PythonObject, newBuilder().publishInModule("_random").basetype().slots(RandomBuiltins.SLOTS)), - PRange("range", PythonObject, newBuilder().publishInModule(J_BUILTINS).slots(RangeBuiltins.SLOTS).doc(""" + PRange("range", PythonObject, newBuilder().publishInModule(J_BUILTINS).sequence().slots(RangeBuiltins.SLOTS).doc(""" range(stop) -> range object range(start, stop[, step]) -> range object @@ -574,23 +578,23 @@ to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1. start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3. These are exactly the valid indices for a list of 4 elements. When step is given, it specifies the increment (or decrement).""")), - PReferenceType("ReferenceType", PythonObject, newBuilder().publishInModule("_weakref").basetype().slots(ReferenceTypeBuiltins.SLOTS)), + PReferenceType("ReferenceType", PythonObject, newBuilder().publishInModule("_weakref").basetype().haveGC().slots(ReferenceTypeBuiltins.SLOTS)), PProxyType("ProxyType", PythonObject, newBuilder().moduleName("weakref").publishInModule("_weakref").slots(ProxyTypeBuiltins.SLOTS)), PCallableProxyType("CallableProxyType", PythonObject, newBuilder().moduleName("weakref").publishInModule("_weakref")), PSentinelIterator("callable_iterator", PythonObject, newBuilder().disallowInstantiation().slots(SentinelIteratorBuiltins.SLOTS)), - PReverseIterator("reversed", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(ReversedBuiltins.SLOTS).doc(""" + PReverseIterator("reversed", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(ReversedBuiltins.SLOTS).doc(""" Return a reverse iterator over the values of the given sequence.""")), - PSet("set", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(BaseSetBuiltins.SLOTS, SetBuiltins.SLOTS).doc(""" + PSet("set", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().slots(BaseSetBuiltins.SLOTS, SetBuiltins.SLOTS).doc(""" set() -> new empty set object set(iterable) -> new set object Build an unordered collection of unique elements.""")), - PSlice("slice", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(SliceBuiltins.SLOTS).doc(""" + PSlice("slice", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(SliceBuiltins.SLOTS).doc(""" slice(stop) slice(start, stop[, step]) Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).""")), - PString("str", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(StringBuiltins.SLOTS).doc(""" + PString("str", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().unicodeSubclass().slots(StringBuiltins.SLOTS).doc(""" str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str @@ -601,20 +605,20 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).""")) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.""")), - PTraceback("traceback", PythonObject, newBuilder().basetype().slots(TracebackBuiltins.SLOTS)), - PTuple("tuple", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(TupleBuiltins.SLOTS).doc(""" + PTraceback("traceback", PythonObject, newBuilder().basetype().haveGC().slots(TracebackBuiltins.SLOTS)), + PTuple("tuple", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().sequence().tupleSubclass().slots(TupleBuiltins.SLOTS).doc(""" Built-in immutable sequence. If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable's items. If the argument is a tuple, the return value is the same object.""")), - PythonModule("module", PythonObject, newBuilder().basetype().addDict(16).slots(ModuleBuiltins.SLOTS).doc(""" + PythonModule("module", PythonObject, newBuilder().basetype().haveGC().addDict(16).slots(ModuleBuiltins.SLOTS).doc(""" Create a module object. The name must be a string; the optional doc argument can have any type.""")), PythonModuleDef("moduledef", PythonObject, newBuilder()), - Super("super", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().slots(SuperBuiltins.SLOTS).doc(""" + Super("super", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(SuperBuiltins.SLOTS).doc(""" super() -> same as super(__class__, ) super(type) -> unbound super object super(type, obj) -> bound super object; requires isinstance(obj, type) @@ -635,7 +639,7 @@ def cmeth(cls, arg): PZip( "zip", PythonObject, - newBuilder().publishInModule(J_BUILTINS).basetype().slots(ZipBuiltins.SLOTS).doc(""" + newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(ZipBuiltins.SLOTS).doc(""" zip(*iterables, strict=False) --> Yield tuples until an input is exhausted. >>> list(zip('abcdefg', range(3), range(4))) @@ -654,7 +658,7 @@ passed as positional arguments to zip(). The i-th element in every tuple PThreadHandle("_ThreadHandle", PythonObject, newBuilder().publishInModule(J__THREAD).slots(ThreadHandleBuiltins.SLOTS)), PSemLock("SemLock", PythonObject, newBuilder().publishInModule("_multiprocessing").basetype().slots(SemLockBuiltins.SLOTS)), PSocket("socket", PythonObject, newBuilder().publishInModule(J__SOCKET).basetype().slots(SocketBuiltins.SLOTS)), - PStaticmethod("staticmethod", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().addDict(24).slots(StaticmethodBuiltins.SLOTS).doc(""" + PStaticmethod("staticmethod", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().addDict(24).slots(StaticmethodBuiltins.SLOTS).doc(""" staticmethod(function, /) -- @@ -696,7 +700,7 @@ It can be called either on the class (e.g. C.f()) or on an instance Class methods are different than C++ or Java static methods. If you want those, see the staticmethod builtin.""")), - PInstancemethod("instancemethod", PythonObject, newBuilder().basetype().addDict().slots(InstancemethodBuiltins.SLOTS).doc(""" + PInstancemethod("instancemethod", PythonObject, newBuilder().basetype().haveGC().addDict().slots(InstancemethodBuiltins.SLOTS).doc(""" instancemethod(function) Bind a function to a class.""")), @@ -747,7 +751,7 @@ It can be called either on the class (e.g. C.f()) or on an instance // Errors and exceptions: // everything after BaseException is considered to be an exception - PBaseException("BaseException", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().addDict(16).slots(BaseExceptionBuiltins.SLOTS).doc(""" + PBaseException("BaseException", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().baseExceptionSubclass().addDict(16).slots(BaseExceptionBuiltins.SLOTS).doc(""" Common base class for all exceptions""")), PBaseExceptionGroup("BaseExceptionGroup", PBaseException, newBuilder().publishInModule(J_BUILTINS).basetype().addDict().slots(BaseExceptionGroupBuiltins.SLOTS).doc(""" A combination of multiple unrelated exceptions.""")), @@ -923,7 +927,7 @@ It can be called either on the class (e.g. C.f()) or on an instance PIncrementalNewlineDecoder("IncrementalNewlineDecoder", PythonObject, newBuilder().publishInModule("_io").basetype().slots(IncrementalNewlineDecoderBuiltins.SLOTS)), PStringIO("StringIO", PTextIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(StringIOBuiltins.SLOTS)), PBytesIO("BytesIO", PBufferedIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(BytesIOBuiltins.SLOTS)), - PBytesIOBuf("_BytesIOBuffer", PythonObject, newBuilder().moduleName("_io").basetype()), + PBytesIOBuf("_BytesIOBuffer", PythonObject, newBuilder().moduleName("_io").basetype().haveGC()), PStatResult( "stat_result", @@ -1065,7 +1069,7 @@ accepted by asctime(), mktime() and strftime(). May be considered as a \tdef compress(data, selectors): \t\t# compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F \t\treturn (d for d, s in zip(data, selectors) if s)""")), - PCycle("cycle", PythonObject, newBuilder().publishInModule("itertools").basetype().slots(CycleBuiltins.SLOTS).doc(""" + PCycle("cycle", PythonObject, newBuilder().publishInModule("itertools").basetype().haveGC().slots(CycleBuiltins.SLOTS).doc(""" Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. @@ -1230,7 +1234,8 @@ def takewhile(predicate, iterable): "time", PythonObject, newBuilder().moduleName("datetime").publishInModule("_datetime").basetype().slots(TimeBuiltins.SLOTS).doc(""" - time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object\n + time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object + All arguments are optional. tzinfo may be None, or an instance of a tzinfo subclass. The remaining arguments may be ints. """)), @@ -1239,7 +1244,8 @@ def takewhile(predicate, iterable): "datetime", PDate, newBuilder().moduleName("datetime").publishInModule("_datetime").basetype().slots(DateTimeBuiltins.SLOTS).doc(""" - datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])\n + datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]]) + The year, month and day arguments are required. tzinfo may be None, or an instance of a tzinfo subclass. The remaining arguments may be ints. """)), @@ -1248,7 +1254,8 @@ def takewhile(predicate, iterable): "IsoCalendarDate", PTuple, newBuilder().moduleName("datetime").publishInModule("_datetime").slots(StructSequenceBuiltins.SLOTS).doc(""" - The result of date.isocalendar() or datetime.isocalendar()\n + The result of date.isocalendar() or datetime.isocalendar() + This object may be accessed either as a tuple of ((year, week, weekday) or via the object attributes as named in the above tuple.""")), @@ -1257,8 +1264,10 @@ def takewhile(predicate, iterable): "timedelta", PythonObject, newBuilder().moduleName("datetime").publishInModule("_datetime").basetype().slots(TimeDeltaBuiltins.SLOTS).doc(""" - Difference between two datetime values.\n - timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)\n + Difference between two datetime values. + + timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0) + All arguments are optional and default to 0. Arguments may be integers or floats, and may be positive or negative.""")), PTzInfo( @@ -1537,11 +1546,9 @@ private static TypeBuilder newBuilder() { private static final class TypeBuilder { private String publishInModule; private String moduleName; - private boolean basetype; - private boolean heaptype; + private long flags = TypeFlags.DEFAULT | TypeFlags.READY | TypeFlags.IMMUTABLETYPE; private boolean addDict; private int dictoffset; - private boolean disallowInstantiation; private TpSlots slots; private String doc; @@ -1559,12 +1566,77 @@ public TypeBuilder moduleName(String moduleName) { } public TypeBuilder basetype() { - this.basetype = true; + flags |= TypeFlags.BASETYPE; return this; } public TypeBuilder heaptype() { - this.heaptype = true; + flags |= TypeFlags.HEAPTYPE; + return this; + } + + public TypeBuilder haveGC() { + flags |= TypeFlags.HAVE_GC; + return this; + } + + public TypeBuilder sequence() { + flags |= TypeFlags.SEQUENCE; + return this; + } + + public TypeBuilder mapping() { + flags |= TypeFlags.MAPPING; + return this; + } + + public TypeBuilder matchSelf() { + flags |= TypeFlags.MATCH_SELF; + return this; + } + + public TypeBuilder methodDescriptor() { + flags |= TypeFlags.METHOD_DESCRIPTOR; + return this; + } + + public TypeBuilder baseExceptionSubclass() { + flags |= TypeFlags.BASE_EXC_SUBCLASS; + return this; + } + + public TypeBuilder typeSubclass() { + flags |= TypeFlags.TYPE_SUBCLASS; + return this; + } + + public TypeBuilder longSubclass() { + flags |= TypeFlags.LONG_SUBCLASS; + return this; + } + + public TypeBuilder bytesSubclass() { + flags |= TypeFlags.BYTES_SUBCLASS; + return this; + } + + public TypeBuilder unicodeSubclass() { + flags |= TypeFlags.UNICODE_SUBCLASS; + return this; + } + + public TypeBuilder tupleSubclass() { + flags |= TypeFlags.TUPLE_SUBCLASS; + return this; + } + + public TypeBuilder listSubclass() { + flags |= TypeFlags.LIST_SUBCLASS; + return this; + } + + public TypeBuilder dictSubclass() { + flags |= TypeFlags.DICT_SUBCLASS; return this; } @@ -1580,7 +1652,7 @@ public TypeBuilder addDict(int dictoffset) { } public TypeBuilder disallowInstantiation() { - this.disallowInstantiation = true; + flags |= TypeFlags.DISALLOW_INSTANTIATION; return this; } @@ -1612,10 +1684,9 @@ public TypeBuilder doc(String doc) { // This is the name qualified by module used for printing. But the actual __qualname__ is just // plain name without module private final TruffleString printName; - private final boolean basetype; + private final long flags; private final boolean isBuiltinWithDict; private final int dictoffset; - private final boolean disallowInstantiation; private final TruffleString doc; // initialized in static constructor @@ -1629,8 +1700,8 @@ public TypeBuilder doc(String doc) { /** * The actual slots including slots inherited from base classes. * - * n.b.: this field is positioned to be at the same offset as the one in - * {@link com.oracle.graal.python.builtins.objects.type.PythonManagedClass#tpSlots}. + * n.b.: this field is positioned to be at the same offset as the {@code tp_slots} field in + * {@link com.oracle.graal.python.builtins.objects.type.PythonManagedClass}. */ private final TpSlots slots; @@ -1644,7 +1715,6 @@ public TypeBuilder doc(String doc) { } else { printName = this.name; } - this.basetype = builder.basetype; this.isBuiltinWithDict = builder.addDict; int dictoffset = 0; if (builder.dictoffset != 0) { @@ -1655,28 +1725,36 @@ public TypeBuilder doc(String doc) { this.dictoffset = dictoffset; this.weaklistoffset = -1; this.declaredSlots = builder.slots != null ? builder.slots : TpSlots.createEmpty(); - boolean disallowInstantiation = builder.disallowInstantiation; - // logic from type_ready_set_new - // base.base == null is a roundabout way to check for base == object - if (declaredSlots.tp_new() == null && base.base == null && !builder.heaptype) { - disallowInstantiation = true; + long flags = builder.flags; + if (base != null) { + long inheritedFlags = base.flags & TypeFlags.SUBCLASS_FLAGS; + if ((inheritedFlags & TypeFlags.BASE_EXC_SUBCLASS) != 0) { + inheritedFlags |= base.flags & TypeFlags.HAVE_GC; + } + flags |= inheritedFlags; + + // logic from type_ready_set_new + // base.base == null is a roundabout way to check for base == object + if (declaredSlots.tp_new() == null && base.base == null && (flags & TypeFlags.HEAPTYPE) == 0) { + flags |= TypeFlags.DISALLOW_INSTANTIATION; + } } if (base == null) { this.slots = declaredSlots; } else { var slotBuilder = base.slots.copy(); slotBuilder.overrideIgnoreGroups(declaredSlots); - if (disallowInstantiation) { + if ((flags & TypeFlags.DISALLOW_INSTANTIATION) != 0) { slotBuilder.set(TpSlots.TpSlotMeta.TP_NEW, null); } this.slots = slotBuilder.build(); } - this.disallowInstantiation = disallowInstantiation; + this.flags = flags; this.doc = toTruffleStringUncached(builder.doc); } public boolean isAcceptableBase() { - return basetype; + return (flags & TypeFlags.BASETYPE) != 0; } public TruffleString getName() { @@ -1699,8 +1777,8 @@ public int getDictoffset() { return dictoffset; } - public boolean disallowInstantiation() { - return disallowInstantiation; + public long getFlags() { + return flags; } public TruffleString getPublishInModule() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java index 7e5e3f206f..7242cb9053 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java @@ -58,28 +58,16 @@ import static com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess.readLongField; import static com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess.writeLongField; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.BASETYPE; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.BASE_EXC_SUBCLASS; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.BYTES_SUBCLASS; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.COLLECTION_FLAGS; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.DEFAULT; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.DICT_SUBCLASS; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.DISALLOW_INSTANTIATION; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.HAVE_GC; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.HEAPTYPE; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.IMMUTABLETYPE; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.IS_ABSTRACT; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.LIST_SUBCLASS; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.LONG_SUBCLASS; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.MANAGED_DICT; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.MAPPING; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.MATCH_SELF; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.METHOD_DESCRIPTOR; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.READY; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.SEQUENCE; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.SUBCLASS_FLAGS; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.TUPLE_SUBCLASS; import static com.oracle.graal.python.builtins.objects.type.TypeFlags.TYPE_SUBCLASS; -import static com.oracle.graal.python.builtins.objects.type.TypeFlags.UNICODE_SUBCLASS; import static com.oracle.graal.python.nodes.HiddenAttr.BASICSIZE; import static com.oracle.graal.python.nodes.HiddenAttr.DICTOFFSET; import static com.oracle.graal.python.nodes.HiddenAttr.ITEMSIZE; @@ -313,7 +301,7 @@ static long doNative(PythonNativeClass clazz) { @TruffleBoundary private static long computeFlags(PythonManagedClass clazz) { if (clazz instanceof PythonBuiltinClass) { - return defaultBuiltinFlags(((PythonBuiltinClass) clazz).getType()); + return ((PythonBuiltinClass) clazz).getType().getFlags(); } // according to 'type_new' in 'typeobject.c', all have DEFAULT, HEAPTYPE, and BASETYPE. // The HAVE_GC is inherited. But we do not mimic this behavior in every detail, so it @@ -348,148 +336,6 @@ private static long computeFlags(PythonManagedClass clazz) { return result; } - private static long defaultBuiltinFlags(PythonBuiltinClassType clazz) { - long result; - switch (clazz) { - case MultibyteCodec: - case PEllipsis: - case PNotImplemented: - case PNoDefault: - case PNone: - result = DEFAULT; - break; - case PythonObject: - case MultibyteIncrementalEncoder: - case MultibyteIncrementalDecoder: - case MultibyteStreamReader: - case MultibyteStreamWriter: - result = DEFAULT | BASETYPE; - break; - case PArray: - result = DEFAULT | BASETYPE | SEQUENCE; - break; - case PythonClass: - case Super: - case PythonModule: - case PReferenceType: - case PProperty: - case PDeque: - case POrderedDict: - case PSimpleQueue: - case PSimpleNamespace: - case PMap: - case PStaticmethod: - case PZip: - case PReverseIterator: - case PCycle: - case PEnumerate: - case PBaseException: - result = DEFAULT | HAVE_GC | BASETYPE; - break; - case PFrozenSet: - case PSet: - result = DEFAULT | HAVE_GC | BASETYPE | MATCH_SELF; - break; - case Boolean: - result = DEFAULT | MATCH_SELF; - break; - case PFunction: - case PBuiltinFunction: - case WrapperDescriptor: - case PLruCacheWrapper: - result = DEFAULT | HAVE_GC | METHOD_DESCRIPTOR; - break; - case PLruListElem: - result = DEFAULT | HAVE_GC; - break; - case PBytesIOBuf: - case PMethod: - case PBuiltinFunctionOrMethod: - case PBuiltinMethod: - case MethodWrapper: - case PInstancemethod: - case GetSetDescriptor: - case MemberDescriptor: - case PFrame: - case PGenerator: - case PSlice: - case PTraceback: - case PDequeIter: - case PDequeRevIter: - case PArrayIterator: - case PAsyncGenerator: - case PCell: - case PIterator: - case PPoll: - result = DEFAULT | HAVE_GC; - break; - case PMappingproxy: - result = DEFAULT | HAVE_GC | MAPPING; - break; - case PMemoryView: - result = DEFAULT | HAVE_GC | SEQUENCE; - break; - case PDict: - result = DEFAULT | HAVE_GC | BASETYPE | MATCH_SELF | MAPPING; - break; - case PDefaultDict: - result = DEFAULT | HAVE_GC | BASETYPE | MAPPING; - break; - case PList: - case PTuple: - result = DEFAULT | HAVE_GC | BASETYPE | MATCH_SELF | SEQUENCE; - break; - case PRange: - result = DEFAULT | SEQUENCE; - break; - case PythonModuleDef: - case Capsule: - result = 0; - break; - case PByteArray: - case PFloat: - case PInt: - case PString: - case PBytes: - result = DEFAULT | BASETYPE | MATCH_SELF; - break; - case PIOBase: - result = DEFAULT | BASETYPE | HEAPTYPE; - break; - default: - // default case; this includes: PythonObject, PCode, PInstancemethod, PNone, - // PNotImplemented, PEllipsis, exceptions - result = DEFAULT; - break; - } - result |= clazz.isAcceptableBase() ? BASETYPE : 0; - result |= clazz.disallowInstantiation() ? DISALLOW_INSTANTIATION : 0; - PythonBuiltinClassType iter = clazz; - while (iter != null) { - if (iter == PythonBuiltinClassType.PBaseException) { - result |= BASE_EXC_SUBCLASS | HAVE_GC; - } else if (iter == PythonBuiltinClassType.PythonClass) { - result |= TYPE_SUBCLASS; - } else if (iter == PythonBuiltinClassType.PInt) { - result |= LONG_SUBCLASS; - } else if (iter == PythonBuiltinClassType.PBytes) { - result |= BYTES_SUBCLASS; - } else if (iter == PythonBuiltinClassType.PString) { - result |= UNICODE_SUBCLASS; - } else if (iter == PythonBuiltinClassType.PTuple) { - result |= TUPLE_SUBCLASS; - } else if (iter == PythonBuiltinClassType.PList) { - result |= LIST_SUBCLASS; - } else if (iter == PythonBuiltinClassType.PDict) { - result |= DICT_SUBCLASS; - } - iter = iter.getBase(); - } - // we always claim that all types are fully initialized - // so far, all builtin types we care about are IMMUTABLE - return result | READY | IMMUTABLETYPE; - } - public static GetTypeFlagsNode getUncached() { return TypeNodesFactory.GetTypeFlagsNodeGen.getUncached(); } From 36f0de5ab255fc40d720e2709134b18d61383842 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 16 Sep 2026 09:35:29 +0200 Subject: [PATCH 2/5] Move itemsize into PythonBuiltinClassType --- .../src/tests/test_type.py | 12 +++++++ .../builtins/PythonBuiltinClassType.java | 34 +++++++++++++------ .../builtins/objects/type/TypeNodes.java | 18 +--------- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_type.py b/graalpython/com.oracle.graal.python.test/src/tests/test_type.py index b00094268e..738e362220 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_type.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_type.py @@ -339,10 +339,22 @@ class SubSlots(BaseSlots, Base): def test_itemsize(): + import types + assert object.__itemsize__ == 0 assert list.__itemsize__ == 0 assert type.__itemsize__ == 40 + assert bytes.__itemsize__ == 1 + assert int.__itemsize__ == 4 + assert bool.__itemsize__ == 4 assert tuple.__itemsize__ == 8 + assert types.CodeType.__itemsize__ == 2 + assert types.GeneratorType.__itemsize__ == 8 + assert types.CoroutineType.__itemsize__ == 8 + assert types.AsyncGeneratorType.__itemsize__ == 8 + assert types.FrameType.__itemsize__ == 8 + assert memoryview.__itemsize__ == 8 + assert type(sys.version_info).__itemsize__ == 8 class C: pass assert C.__itemsize__ == 0 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index 0637f0eea0..54f5a76ec2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -320,7 +320,7 @@ public enum PythonBuiltinClassType implements TruffleObject { When called, it accepts no arguments and returns a new featureless instance that has no instance attributes and cannot be given any. """)), - PythonClass("type", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().typeSubclass().addDict(264).slots(TypeBuiltins.SLOTS).doc(""" + PythonClass("type", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().typeSubclass().addDict(264).itemsize(40).slots(TypeBuiltins.SLOTS).doc(""" type(object) -> the object's type type(name, bases, dict, **kwds) -> a new type""")), PArray("array", PythonObject, newBuilder().publishInModule("array").basetype().sequence().slots(ArrayBuiltins.SLOTS)), @@ -358,7 +358,7 @@ public enum PythonBuiltinClassType implements TruffleObject { - a bytes or a buffer object - any object implementing the buffer API. - an integer""")), - PBytes("bytes", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().bytesSubclass().slots(BytesCommonBuiltins.SLOTS, BytesBuiltins.SLOTS).doc(""" + PBytes("bytes", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().bytesSubclass().itemsize(1).slots(BytesCommonBuiltins.SLOTS, BytesBuiltins.SLOTS).doc(""" bytes(iterable_of_ints) -> bytes bytes(string, encoding[, errors]) -> bytes bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer @@ -460,7 +460,7 @@ Return an iterator yielding those items of iterable for which function(item) PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().slots(FloatBuiltins.SLOTS).doc(""" Convert a string or number to a floating point number, if possible.""")), - PFrame("frame", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(FrameBuiltins.SLOTS)), + PFrame("frame", PythonObject, newBuilder().haveGC().disallowInstantiation().itemsize(8).slots(FrameBuiltins.SLOTS)), PFrameLocalsProxy("FrameLocalsProxy", PythonObject, newBuilder().disallowInstantiation().slots(FrameLocalsProxyBuiltins.SLOTS)), PFrozenSet( "frozenset", @@ -471,12 +471,12 @@ Return an iterator yielding those items of iterable for which function(item) Build an immutable unordered collection of unique elements.""")), PFunction("function", PythonObject, newBuilder().haveGC().methodDescriptor().addDict().slots(AbstractFunctionBuiltins.SLOTS, FunctionBuiltins.SLOTS)), - PGenerator("generator", PythonObject, newBuilder().haveGC().disallowInstantiation().slots(GeneratorBuiltins.SLOTS)), - PCoroutine("coroutine", PythonObject, newBuilder().slots(CoroutineBuiltins.SLOTS)), + PGenerator("generator", PythonObject, newBuilder().haveGC().disallowInstantiation().itemsize(8).slots(GeneratorBuiltins.SLOTS)), + PCoroutine("coroutine", PythonObject, newBuilder().itemsize(8).slots(CoroutineBuiltins.SLOTS)), PCoroutineWrapper("coroutine_wrapper", PythonObject, newBuilder().slots(CoroutineWrapperBuiltins.SLOTS)), - PAsyncGenerator("async_generator", PythonObject, newBuilder().haveGC().slots(AsyncGeneratorBuiltins.SLOTS)), + PAsyncGenerator("async_generator", PythonObject, newBuilder().haveGC().itemsize(8).slots(AsyncGeneratorBuiltins.SLOTS)), PAnextAwaitable("anext_awaitable", PythonObject, newBuilder().slots(ANextAwaitableBuiltins.SLOTS)), - PInt("int", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().longSubclass().slots(IntBuiltins.SLOTS).doc(""" + PInt("int", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().matchSelf().longSubclass().itemsize(4).slots(IntBuiltins.SLOTS).doc(""" int([x]) -> integer int(x, base=10) -> integer @@ -489,7 +489,7 @@ Return an iterator yielding those items of iterable for which function(item) given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.""")), - Boolean("bool", PInt, newBuilder().publishInModule(J_BUILTINS).matchSelf().slots(BoolBuiltins.SLOTS).doc(""" + Boolean("bool", PInt, newBuilder().publishInModule(J_BUILTINS).matchSelf().itemsize(4).slots(BoolBuiltins.SLOTS).doc(""" bool(x) -> bool Returns True when the argument x is true, False otherwise. @@ -504,7 +504,7 @@ Return an iterator yielding those items of iterable for which function(item) PMemoryView( "memoryview", PythonObject, - newBuilder().publishInModule(J_BUILTINS).haveGC().sequence().slots(MemoryViewBuiltins.SLOTS).doc(""" + newBuilder().publishInModule(J_BUILTINS).haveGC().sequence().itemsize(8).slots(MemoryViewBuiltins.SLOTS).doc(""" Create a new memoryview object which references the given object.""")), PMemoryViewIterator("memory_iterator", PythonObject, newBuilder().slots(MemoryViewIteratorBuiltins.SLOTS)), PAsyncGenASend("async_generator_asend", PythonObject, newBuilder().slots(AsyncGenSendBuiltins.SLOTS)), @@ -606,7 +606,7 @@ or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.""")), PTraceback("traceback", PythonObject, newBuilder().basetype().haveGC().slots(TracebackBuiltins.SLOTS)), - PTuple("tuple", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().sequence().tupleSubclass().slots(TupleBuiltins.SLOTS).doc(""" + PTuple("tuple", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().matchSelf().sequence().tupleSubclass().itemsize(8).slots(TupleBuiltins.SLOTS).doc(""" Built-in immutable sequence. If no argument is given, the constructor returns an empty tuple. @@ -632,7 +632,7 @@ class C(B): @classmethod def cmeth(cls, arg): super().cmeth(arg)""")), - PCode("code", PythonObject, newBuilder().slots(CodeBuiltins.SLOTS)), + PCode("code", PythonObject, newBuilder().itemsize(2).slots(CodeBuiltins.SLOTS)), PGenericAlias("GenericAlias", PythonObject, newBuilder().publishInModule(J_TYPES).basetype().slots(GenericAliasBuiltins.SLOTS)), PGenericAliasIterator("generic_alias_iterator", PythonObject, newBuilder().slots(GenericAliasIteratorBuiltins.SLOTS)), PUnionType("UnionType", PythonObject, newBuilder().publishInModule(J_TYPES).slots(UnionTypeBuiltins.SLOTS)), @@ -1549,6 +1549,7 @@ private static final class TypeBuilder { private long flags = TypeFlags.DEFAULT | TypeFlags.READY | TypeFlags.IMMUTABLETYPE; private boolean addDict; private int dictoffset; + private int itemsize; private TpSlots slots; private String doc; @@ -1651,6 +1652,11 @@ public TypeBuilder addDict(int dictoffset) { return this; } + public TypeBuilder itemsize(int itemsize) { + this.itemsize = itemsize; + return this; + } + public TypeBuilder disallowInstantiation() { flags |= TypeFlags.DISALLOW_INSTANTIATION; return this; @@ -1687,6 +1693,7 @@ public TypeBuilder doc(String doc) { private final long flags; private final boolean isBuiltinWithDict; private final int dictoffset; + private final int itemsize; private final TruffleString doc; // initialized in static constructor @@ -1723,6 +1730,7 @@ public TypeBuilder doc(String doc) { dictoffset = base.dictoffset; } this.dictoffset = dictoffset; + this.itemsize = builder.itemsize != 0 ? builder.itemsize : base != null ? base.itemsize : 0; this.weaklistoffset = -1; this.declaredSlots = builder.slots != null ? builder.slots : TpSlots.createEmpty(); long flags = builder.flags; @@ -1777,6 +1785,10 @@ public int getDictoffset() { return dictoffset; } + public int getItemsize() { + return itemsize; + } + public long getFlags() { return flags; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java index 7242cb9053..d5194860bf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java @@ -2493,23 +2493,7 @@ public static long executeUncached(Object cls) { @Specialization static long lookup(Object cls, @Cached(inline = false) CExtNodes.LookupNativeI64MemberFromBaseNode lookup) { - return lookup.execute(cls, PyTypeObject__tp_itemsize, ITEMSIZE, GetItemSizeNode::getBuiltinTypeItemsize); - } - - private static int getBuiltinTypeItemsize(PythonBuiltinClassType cls) { - // Our formatter currently forces all the case labels on a single line - // @formatter:off - return switch (cls) { - case PBytes -> 1; - case PCode -> 2; - case PInt, Boolean -> 4; - case PAsyncGenerator, PFlags, PHashInfo, PTuple, PCoroutine, PGenerator, PThreadInfo, PMemoryView, - PStatResult, PUnameResult, PStructTime, PFloatInfo, PStatvfsResult, PIntInfo, PFrame, - PTerminalSize, PUnraisableHookArgs, PExceptHookArgs -> 8; - case PythonClass -> 40; - default -> 0; - }; - // @formatter:on + return lookup.execute(cls, PyTypeObject__tp_itemsize, ITEMSIZE, PythonBuiltinClassType::getItemsize); } } From 0919a52d668e8f3e7a71e8a1ecb8f6b3fdc908cc Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 16 Sep 2026 14:36:53 +0200 Subject: [PATCH 3/5] Fix native tzinfo registration --- graalpython/com.oracle.graal.python.cext/src/datetime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python.cext/src/datetime.c b/graalpython/com.oracle.graal.python.cext/src/datetime.c index 881cd6a3a3..0e9158c35a 100644 --- a/graalpython/com.oracle.graal.python.cext/src/datetime.c +++ b/graalpython/com.oracle.graal.python.cext/src/datetime.c @@ -7669,7 +7669,7 @@ GraalPyPrivate_InitNativeDateTime(void) (intptr_t)&PyDateTime_DateTimeType, (intptr_t)"datetime.datetime", (intptr_t)&PyDateTime_TimeType, (intptr_t)"datetime.time", (intptr_t)&PyDateTime_DeltaType, (intptr_t)"datetime.timedelta", - (intptr_t)&PyDateTime_TZInfoType, (intptr_t)"datetime.timezone", + (intptr_t)&PyDateTime_TZInfoType, (intptr_t)"datetime.tzinfo", 0, 0 }; GraalPyPrivate_InitBuiltinTypesAndStructs(datetime_types); From 1415046720fa9b3a9219e86f0b2f73c006f49510 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 16 Sep 2026 14:39:59 +0200 Subject: [PATCH 4/5] Fix managed-native flag inconsistencies --- .../src/tests/test_type.py | 3 ++ .../builtins/PythonBuiltinClassType.java | 13 ++++--- .../modules/WeakRefModuleBuiltins.java | 7 ---- .../capi/transitions/ToNativeTypeNode.java | 34 ++++++------------- .../builtins/objects/type/TypeFlags.java | 3 +- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_type.py b/graalpython/com.oracle.graal.python.test/src/tests/test_type.py index 738e362220..de60c23468 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_type.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_type.py @@ -227,6 +227,7 @@ def testfunction(self): TPFLAGS_HAVE_GC = 1 << 14 TPFLAGS_METHOD_DESCRIPTOR = 1 << 17 TPFLAGS_MATCH_SELF = 1 << 22 + TPFLAGS_ITEMS_AT_END = 1 << 23 TPFLAGS_LONG_SUBCLASS = 1 << 24 TPFLAGS_LIST_SUBCLASS = 1 << 25 TPFLAGS_TUPLE_SUBCLASS = 1 << 26 @@ -240,6 +241,7 @@ def testfunction(self): assert typing.Generic.__flags__ & TPFLAGS_HEAPTYPE assert object.__flags__ & TPFLAGS_BASETYPE + assert not slice.__flags__ & TPFLAGS_BASETYPE assert type.__flags__ & TPFLAGS_HAVE_GC assert list.__flags__ & TPFLAGS_SEQUENCE assert list.__flags__ & TPFLAGS_MATCH_SELF @@ -247,6 +249,7 @@ def testfunction(self): assert BaseException.__flags__ & TPFLAGS_BASE_EXC_SUBCLASS assert ValueError.__flags__ & TPFLAGS_BASE_EXC_SUBCLASS assert ValueError.__flags__ & TPFLAGS_HAVE_GC + assert type.__flags__ & TPFLAGS_ITEMS_AT_END assert type.__flags__ & TPFLAGS_TYPE_SUBCLASS assert not type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, "masked __flags__ = {}, expected {}".format(type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, 0) assert type(list.append).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, "masked __flags__ = {}, expected {}".format(type(repr).__flags__ & TPFLAGS_METHOD_DESCRIPTOR, TPFLAGS_METHOD_DESCRIPTOR) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index 54f5a76ec2..00592f0513 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -320,7 +320,7 @@ public enum PythonBuiltinClassType implements TruffleObject { When called, it accepts no arguments and returns a new featureless instance that has no instance attributes and cannot be given any. """)), - PythonClass("type", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().typeSubclass().addDict(264).itemsize(40).slots(TypeBuiltins.SLOTS).doc(""" + PythonClass("type", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().typeSubclass().addDict(264).itemsize(40).itemsAtEnd().slots(TypeBuiltins.SLOTS).doc(""" type(object) -> the object's type type(name, bases, dict, **kwds) -> a new type""")), PArray("array", PythonObject, newBuilder().publishInModule("array").basetype().sequence().slots(ArrayBuiltins.SLOTS)), @@ -579,8 +579,8 @@ to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1. These are exactly the valid indices for a list of 4 elements. When step is given, it specifies the increment (or decrement).""")), PReferenceType("ReferenceType", PythonObject, newBuilder().publishInModule("_weakref").basetype().haveGC().slots(ReferenceTypeBuiltins.SLOTS)), - PProxyType("ProxyType", PythonObject, newBuilder().moduleName("weakref").publishInModule("_weakref").slots(ProxyTypeBuiltins.SLOTS)), - PCallableProxyType("CallableProxyType", PythonObject, newBuilder().moduleName("weakref").publishInModule("_weakref")), + PProxyType("ProxyType", PythonObject, newBuilder().haveGC().moduleName("weakref").publishInModule("_weakref").slots(ProxyTypeBuiltins.SLOTS)), + PCallableProxyType("CallableProxyType", PythonObject, newBuilder().haveGC().moduleName("weakref").publishInModule("_weakref")), PSentinelIterator("callable_iterator", PythonObject, newBuilder().disallowInstantiation().slots(SentinelIteratorBuiltins.SLOTS)), PReverseIterator("reversed", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(ReversedBuiltins.SLOTS).doc(""" Return a reverse iterator over the values of the given sequence.""")), @@ -589,7 +589,7 @@ When step is given, it specifies the increment (or decrement).""")), set(iterable) -> new set object Build an unordered collection of unique elements.""")), - PSlice("slice", PythonObject, newBuilder().publishInModule(J_BUILTINS).basetype().haveGC().slots(SliceBuiltins.SLOTS).doc(""" + PSlice("slice", PythonObject, newBuilder().publishInModule(J_BUILTINS).haveGC().slots(SliceBuiltins.SLOTS).doc(""" slice(stop) slice(start, stop[, step]) @@ -1596,6 +1596,11 @@ public TypeBuilder matchSelf() { return this; } + public TypeBuilder itemsAtEnd() { + flags |= TypeFlags.ITEMS_AT_END; + return this; + } + public TypeBuilder methodDescriptor() { flags |= TypeFlags.METHOD_DESCRIPTOR; return this; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WeakRefModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WeakRefModuleBuiltins.java index c43a90a486..715d4c95b8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WeakRefModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WeakRefModuleBuiltins.java @@ -43,8 +43,6 @@ import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.removeNativeWeakRef; import static com.oracle.graal.python.nodes.BuiltinNames.J__WEAKREF; import static com.oracle.graal.python.nodes.BuiltinNames.T__WEAKREF; -import static com.oracle.graal.python.nodes.BuiltinNames.T_PROXY_TYPE; -import static com.oracle.graal.python.nodes.BuiltinNames.T_CALLABLE_PROXY_TYPE; import static com.oracle.graal.python.nodes.HiddenAttr.WEAK_REF_QUEUE; import static com.oracle.graal.python.nodes.StringLiterals.T_REF; @@ -65,8 +63,6 @@ import com.oracle.graal.python.builtins.objects.referencetype.PReferenceType; import com.oracle.graal.python.builtins.objects.referencetype.PReferenceType.WeakRefStorage; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; -import com.oracle.graal.python.builtins.objects.type.TypeFlags; -import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.nodes.HiddenAttr; import com.oracle.graal.python.nodes.WriteUnraisableNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; @@ -184,9 +180,6 @@ public void postInitialize(Python3Core core) { PythonBuiltinClass refType = core.lookupType(PythonBuiltinClassType.PReferenceType); weakrefModule.setAttribute(T_REF, refType); HiddenAttr.WriteNode.executeUncached(refType, WEAK_REF_QUEUE, weakRefQueue); - // FIXME we should intrinsify those types - TypeNodes.SetTypeFlagsNode.executeUncached(weakrefModule.getAttribute(T_PROXY_TYPE), TypeFlags.DEFAULT | TypeFlags.HAVE_GC); - TypeNodes.SetTypeFlagsNode.executeUncached(weakrefModule.getAttribute(T_CALLABLE_PROXY_TYPE), TypeFlags.DEFAULT | TypeFlags.HAVE_GC); final PythonContext ctx = core.getContext(); core.getContext().registerAsyncAction(() -> { if (!ctx.getGcState().isEnabled()) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ToNativeTypeNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ToNativeTypeNode.java index a98b71a7a7..61e2af7700 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ToNativeTypeNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ToNativeTypeNode.java @@ -90,7 +90,6 @@ import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetMroStorageNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetSubclassesNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetTypeFlagsNode; -import com.oracle.graal.python.builtins.objects.type.TypeNodes.SetTypeFlagsNode; import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.GetTypeFlagsNodeGen; import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.SetBasicSizeNodeGen; import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.SetItemSizeNodeGen; @@ -158,8 +157,6 @@ static void initializeType(PythonManagedClass clazz, long mem, boolean heaptype, TpSlots slots = GetTpSlotsNode.executeUncached(clazz); boolean isType = IsBuiltinClassExactProfile.profileClassSlowPath(clazz, PythonBuiltinClassType.PythonClass); - GetTypeFlagsNode getTypeFlagsNode = GetTypeFlagsNodeGen.getUncached(); - PythonContext ctx = PythonContext.get(null); PythonLanguage language = ctx.getLanguage(); @@ -173,15 +170,6 @@ static void initializeType(PythonManagedClass clazz, long mem, boolean heaptype, writePtrField(mem, PyObject__ob_type, PythonToNativeInternalNode.executeUncached(promotedType, false)); } - long flags = getTypeFlagsNode.execute(clazz); - /* - * Our datetime classes are declared as static types in C, but are implemented as - * pure-python heaptypes. Make them into static types on the C-side. - */ - if (!heaptype) { - flags &= ~TypeFlags.HEAPTYPE; - } - Object base = GetBaseClassNode.executeUncached(clazz); if (base == null) { base = PNone.NO_VALUE; @@ -222,6 +210,8 @@ static void initializeType(PythonManagedClass clazz, long mem, boolean heaptype, writePtrField(mem, CFields.PyTypeObject__tp_as_sequence, asSequence); writePtrField(mem, CFields.PyTypeObject__tp_as_mapping, asMapping); writePtrField(mem, CFields.PyTypeObject__tp_as_buffer, asBuffer); + + long flags = GetTypeFlagsNodeGen.getUncached().execute(clazz); writeLongField(mem, CFields.PyTypeObject__tp_flags, flags); // return a C string wrapper that really allocates 'char*' on TO_NATIVE @@ -370,17 +360,7 @@ public static int wrapStaticTypeStructForManagedClass(PythonManagedClass clazz, HiddenAttr.WriteLongNode.executeUncached(clazz, HiddenAttr.AS_BUFFER, as_buffer); } - /* - * Initialize type flags: If the native type, we are wrapping, already defines 'tp_flags', - * we use it because those must stay consistent with slots. For example, native - * tp_new/tp_alloc/tp_dealloc/tp_free functions must be consistent with - * 'Py_TPFLAGS_HAVE_GC'. - */ - long flags = readLongField(pointer, CFields.PyTypeObject__tp_flags); - if (flags == 0) { - flags = GetTypeFlagsNode.executeUncached(clazz) | TypeFlags.READY | TypeFlags.IMMUTABLETYPE; - } - SetTypeFlagsNode.executeUncached(clazz, flags); + assert checkFlags(clazz, pointer); // TODO(fa): revisit this: static classes are immortal; we don't need a // PythonObjectReference @@ -388,4 +368,12 @@ public static int wrapStaticTypeStructForManagedClass(PythonManagedClass clazz, assert clazz.isNative(); return nativeTypeId; } + + private static boolean checkFlags(PythonManagedClass clazz, long pointer) { + long nativeFlags = readLongField(pointer, CFields.PyTypeObject__tp_flags); + long expectedFlags = nativeFlags | TypeFlags.READY | TypeFlags.IMMUTABLETYPE; + long managedFlags = GetTypeFlagsNode.getUncached().execute(clazz); + assert nativeFlags == 0 || managedFlags == expectedFlags : String.format("Mismatched flags for builtin type %s: managed 0x%x, native 0x%x", clazz.getQualName(), managedFlags, expectedFlags); + return true; + } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeFlags.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeFlags.java index 3115ff1d58..c8cbc75071 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeFlags.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -64,6 +64,7 @@ public abstract class TypeFlags { public static final long VALID_VERSION_TAG = (1L << 19); public static final long IS_ABSTRACT = (1L << 20); public static final long MATCH_SELF = (1L << 22); + public static final long ITEMS_AT_END = (1L << 23); public static final long LONG_SUBCLASS = (1L << 24); public static final long LIST_SUBCLASS = (1L << 25); public static final long TUPLE_SUBCLASS = (1L << 26); From 13070657e1a3090fba9a64959488e890370c9eae Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 16 Sep 2026 14:41:25 +0200 Subject: [PATCH 5/5] Simplify getting flags for builtin types --- .../objects/tuple/StructSequence.java | 15 ++++--- .../builtins/objects/type/TypeNodes.java | 41 ++++++------------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequence.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequence.java index 968507476a..9f78259d3b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequence.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequence.java @@ -162,10 +162,13 @@ public static void initType(PythonContext context, PythonAbstractClass klass, De assert IsSubtypeNode.getUncached().execute(klass, PythonBuiltinClassType.PTuple); PythonLanguage language = context.getLanguage(); - long flags = TypeNodes.GetTypeFlagsNode.executeUncached(klass); - if ((flags & TypeFlags.IMMUTABLETYPE) != 0) { - // Temporarily open the type for mutation - TypeNodes.SetTypeFlagsNode.executeUncached(klass, flags & ~TypeFlags.IMMUTABLETYPE); + long flags = 0; + if (!(klass instanceof PythonBuiltinClass)) { + flags = TypeNodes.GetTypeFlagsNode.executeUncached(klass); + if ((flags & TypeFlags.IMMUTABLETYPE) != 0) { + // Temporarily open the type for mutation + TypeNodes.SetTypeFlagsNode.executeUncached(klass, flags & ~TypeFlags.IMMUTABLETYPE); + } } // create descriptors for accessing named fields by their names @@ -213,7 +216,9 @@ public static void initType(PythonContext context, PythonAbstractClass klass, De writeAttrNode.execute(klass, T_N_FIELDS, desc.fieldNames.length); writeAttrNode.execute(klass, T_N_UNNAMED_FIELDS, unnamedFields); - TypeNodes.SetTypeFlagsNode.executeUncached(klass, flags); + if ((flags & TypeFlags.IMMUTABLETYPE) != 0) { + TypeNodes.SetTypeFlagsNode.executeUncached(klass, flags); + } } private static void copyMethod(PythonLanguage language, PythonAbstractClass klass, TruffleString name, PythonBuiltinClass template) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java index d5194860bf..a6890a2d5d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java @@ -267,16 +267,17 @@ public static long executeUncached(Object clazz) { } @Specialization - static long doBuiltinClassType(PythonBuiltinClassType clazz, - @Bind Node inliningTarget, - @Shared("read") @Cached HiddenAttr.ReadNode readHiddenFlagsNode, - @Shared("write") @Cached HiddenAttr.WriteNode writeHiddenFlagsNode, - @Shared("profile") @Cached InlinedCountingConditionProfile profile) { - return doManaged(PythonContext.get(inliningTarget).getCore().lookupType(clazz), inliningTarget, readHiddenFlagsNode, writeHiddenFlagsNode, profile); + static long doBuiltinClassType(PythonBuiltinClassType clazz) { + return clazz.getFlags(); } @Specialization - static long doManaged(PythonManagedClass clazz, + static long doBuiltinClass(PythonBuiltinClass clazz) { + return clazz.getType().getFlags(); + } + + @Specialization + static long doManaged(PythonClass clazz, @Bind Node inliningTarget, @Shared("read") @Cached HiddenAttr.ReadNode readHiddenFlagsNode, @Shared("write") @Cached HiddenAttr.WriteNode writeHiddenFlagsNode, @@ -293,16 +294,12 @@ static long doManaged(PythonManagedClass clazz, } @Specialization - @InliningCutoff static long doNative(PythonNativeClass clazz) { return readLongField(clazz.getPtr(), PyTypeObject__tp_flags); } @TruffleBoundary - private static long computeFlags(PythonManagedClass clazz) { - if (clazz instanceof PythonBuiltinClass) { - return ((PythonBuiltinClass) clazz).getType().getFlags(); - } + private static long computeFlags(PythonClass clazz) { // according to 'type_new' in 'typeobject.c', all have DEFAULT, HEAPTYPE, and BASETYPE. // The HAVE_GC is inherited. But we do not mimic this behavior in every detail, so it // should be fine to just set it. @@ -316,21 +313,13 @@ private static long computeFlags(PythonManagedClass clazz) { result |= MANAGED_DICT; } - PythonContext context = PythonContext.get(null); // flags are inherited MroSequenceStorage mroStorage = GetMroStorageNode.executeUncached(clazz); int n = mroStorage.length(); for (int i = 0; i < n; i++) { Object mroEntry = SequenceStorageNodes.GetItemDynamicNode.executeUncached(mroStorage, i); - if (mroEntry instanceof PythonBuiltinClassType) { - mroEntry = context.getCore().lookupType((PythonBuiltinClassType) mroEntry); - } - if (mroEntry instanceof PythonAbstractNativeObject) { - result = setFlags(result, doNative((PythonAbstractNativeObject) mroEntry)); - } else if (mroEntry != clazz && mroEntry instanceof PythonManagedClass) { - long flags = doManaged((PythonManagedClass) mroEntry, null, HiddenAttr.ReadNode.getUncached(), HiddenAttr.WriteNode.getUncached(), - InlinedCountingConditionProfile.getUncached()); - result = setFlags(result, flags); + if (mroEntry != clazz) { + result = setFlags(result, GetTypeFlagsNode.getUncached().execute(mroEntry)); } } return result; @@ -353,13 +342,7 @@ public static void executeUncached(Object clazz, long flags) { } @Specialization - static void doPBCT(Node inliningTarget, PythonBuiltinClassType clazz, long flags, - @Shared("write") @Cached HiddenAttr.WriteNode writeHiddenFlagsNode) { - doManaged(inliningTarget, PythonContext.get(inliningTarget).getCore().lookupType(clazz), flags, writeHiddenFlagsNode); - } - - @Specialization - static void doManaged(Node inliningTarget, PythonManagedClass clazz, long flags, + static void doManaged(Node inliningTarget, PythonClass clazz, long flags, @Shared("write") @Cached HiddenAttr.WriteNode writeHiddenFlagsNode) { writeHiddenFlagsNode.execute(inliningTarget, clazz, HiddenAttr.FLAGS, flags); }