Skip to content

Commit 09b7f19

Browse files
committed
[GR-31832] Add isType support for sub native classes
PullRequest: graalpython/1830
2 parents 03bbe91 + c711708 commit 09b7f19

File tree

6 files changed

+81
-19
lines changed

6 files changed

+81
-19
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,3 +789,7 @@ void register_native_slots(PyTypeObject* managed_class, PyGetSetDef* getsets, Py
789789
polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_Set_Native_Slots", native_type_to_java(managed_class), native_pointer_to_java(getsets), native_pointer_to_java(members));
790790
}
791791
}
792+
793+
int truffle_subclass_check(PyObject* type) {
794+
return PyType_FastSubclass(Py_TYPE(type), Py_TPFLAGS_TYPE_SUBCLASS);
795+
}

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,48 @@ def test_repr(self):
180180
assert False
181181
assert True
182182

183+
def test_base_type(self):
184+
AcceptableBaseType = CPyExtType("AcceptableBaseType",
185+
'''
186+
static PyObject *
187+
TestBase_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
188+
{
189+
return PyType_Type.tp_new(type, args, kwds);
190+
}
191+
PyTypeObject TestBase_Type = {
192+
PyVarObject_HEAD_INIT(NULL, 0)
193+
.tp_name = "TestBase",
194+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
195+
};
196+
197+
static int
198+
AcceptableBaseType_traverse(AcceptableBaseTypeObject *self, visitproc visit, void *arg) {
199+
// This helps to avoid setting 'Py_TPFLAGS_HAVE_GC'
200+
// see typeobject.c:inherit_special:241
201+
return 0;
202+
}
203+
204+
static int
205+
AcceptableBaseType_clear(AcceptableBaseTypeObject *self) {
206+
// This helps to avoid setting 'Py_TPFLAGS_HAVE_GC'
207+
// see typeobject.c:inherit_special:241
208+
return 0;
209+
}
210+
''',
211+
tp_traverse="(traverseproc)AcceptableBaseType_traverse",
212+
tp_clear="(inquiry)AcceptableBaseType_clear",
213+
ready_code='''
214+
TestBase_Type.tp_base = &PyType_Type;
215+
if (PyType_Ready(&TestBase_Type) < 0)
216+
return NULL;
217+
218+
Py_TYPE(&AcceptableBaseTypeType) = &TestBase_Type;
219+
AcceptableBaseTypeType.tp_base = &PyType_Type;''',
220+
)
221+
class Foo(AcceptableBaseType):
222+
# This shouldn't fail
223+
pass
224+
183225
def test_new(self):
184226
TestNew = CPyExtType("TestNew",
185227
'''static PyObject* testnew_new(PyTypeObject* cls, PyObject* a, PyObject* b) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import java.util.regex.Pattern;
5757

5858
import com.oracle.graal.python.PythonLanguage;
59+
import com.oracle.graal.python.builtins.Python3Core;
5960
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
6061
import com.oracle.graal.python.builtins.modules.BuiltinFunctions.GetAttrNode;
6162
import com.oracle.graal.python.builtins.modules.PythonCextBuiltins;
@@ -147,7 +148,6 @@
147148
import com.oracle.graal.python.nodes.util.CastToJavaStringNodeGen;
148149
import com.oracle.graal.python.runtime.PythonContext;
149150
import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode;
150-
import com.oracle.graal.python.builtins.Python3Core;
151151
import com.oracle.graal.python.runtime.PythonOptions;
152152
import com.oracle.graal.python.runtime.exception.PException;
153153
import com.oracle.graal.python.runtime.exception.PythonErrorType;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/NativeCAPISymbol.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
201201
FUN_GET_PY_SSIZE_PTR_T_TYPEID("get_Py_ssize_ptr_t_typeid"),
202202
FUN_TUPLE_SUBTYPE_NEW("tuple_subtype_new"),
203203
FUN_FLOAT_SUBTYPE_NEW("float_subtype_new"),
204+
FUN_SUBCLASS_CHECK("truffle_subclass_check"),
204205
FUN_MEMCPY_BYTES("truffle_memcpy_bytes"),
205206
FUN_UNICODE_SUBTYPE_NEW("unicode_subtype_new");
206207

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
4444
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
45+
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_SUBCLASS_CHECK;
4546
import static com.oracle.graal.python.builtins.objects.type.TypeBuiltins.TYPE_FLAGS;
4647
import static com.oracle.graal.python.builtins.objects.type.TypeBuiltins.TYPE_ITEMSIZE;
4748
import static com.oracle.graal.python.builtins.objects.type.TypeFlags.BASETYPE;
@@ -1380,34 +1381,37 @@ public abstract static class IsTypeNode extends Node {
13801381
public abstract boolean execute(Object obj);
13811382

13821383
@Specialization
1383-
boolean doManagedClass(@SuppressWarnings("unused") PythonClass obj) {
1384+
static boolean doManagedClass(@SuppressWarnings("unused") PythonClass obj) {
13841385
return true;
13851386
}
13861387

13871388
@Specialization
1388-
boolean doManagedClass(@SuppressWarnings("unused") PythonBuiltinClass obj) {
1389+
static boolean doManagedClass(@SuppressWarnings("unused") PythonBuiltinClass obj) {
13891390
return true;
13901391
}
13911392

13921393
@Specialization
1393-
boolean doBuiltinType(@SuppressWarnings("unused") PythonBuiltinClassType obj) {
1394+
static boolean doBuiltinType(@SuppressWarnings("unused") PythonBuiltinClassType obj) {
13941395
return true;
13951396
}
13961397

13971398
@Specialization
1398-
boolean doNativeClass(PythonAbstractNativeObject obj,
1399+
static boolean doNativeClass(PythonAbstractNativeObject obj,
13991400
@Cached IsBuiltinClassProfile profile,
1400-
@Cached GetClassNode getClassNode) {
1401-
// TODO(fa): this check may not be enough since a type object may indirectly inherit
1402-
// from 'type'
1403-
// CPython has two different checks if some object is a type:
1404-
// 1. test if type flag 'Py_TPFLAGS_TYPE_SUBCLASS' is set
1405-
// 2. test if attribute '__bases__' is a tuple
1406-
return profile.profileClass(getClassNode.execute(obj), PythonBuiltinClassType.PythonClass);
1401+
@Cached GetClassNode getClassNode,
1402+
@Cached CExtNodes.PCallCapiFunction nativeTypeCheck) {
1403+
Object type = getClassNode.execute(obj);
1404+
if (profile.profileClass(type, PythonBuiltinClassType.PythonClass)) {
1405+
return true;
1406+
}
1407+
if (PythonNativeClass.isInstance(type)) {
1408+
return (int) nativeTypeCheck.call(FUN_SUBCLASS_CHECK, obj.getPtr()) == 1;
1409+
}
1410+
return false;
14071411
}
14081412

14091413
@Fallback
1410-
boolean doOther(@SuppressWarnings("unused") Object obj) {
1414+
static boolean doOther(@SuppressWarnings("unused") Object obj) {
14111415
return false;
14121416
}
14131417

@@ -1477,37 +1481,43 @@ public abstract static class GetInstanceShape extends PNodeWithContext {
14771481
public abstract Shape execute(Object clazz);
14781482

14791483
@Specialization(guards = "clazz == cachedClazz", limit = "1")
1480-
Shape doBuiltinClassTypeCached(@SuppressWarnings("unused") PythonBuiltinClassType clazz,
1484+
static Shape doBuiltinClassTypeCached(@SuppressWarnings("unused") PythonBuiltinClassType clazz,
14811485
@Shared("lang") @CachedLanguage PythonLanguage lang,
14821486
@Cached("clazz") PythonBuiltinClassType cachedClazz) {
14831487
return cachedClazz.getInstanceShape(lang);
14841488
}
14851489

14861490
@Specialization(replaces = "doBuiltinClassTypeCached")
1487-
Shape doBuiltinClassType(PythonBuiltinClassType clazz,
1491+
static Shape doBuiltinClassType(PythonBuiltinClassType clazz,
14881492
@Shared("lang") @CachedLanguage PythonLanguage lang) {
14891493
return clazz.getInstanceShape(lang);
14901494
}
14911495

14921496
@Specialization(guards = "clazz == cachedClazz", assumptions = "singleContextAssumption()")
1493-
Shape doBuiltinClassCached(@SuppressWarnings("unused") PythonBuiltinClass clazz,
1497+
static Shape doBuiltinClassCached(@SuppressWarnings("unused") PythonBuiltinClass clazz,
14941498
@Cached("clazz") PythonBuiltinClass cachedClazz) {
14951499
return cachedClazz.getInstanceShape();
14961500
}
14971501

14981502
@Specialization(guards = "clazz == cachedClazz", assumptions = "singleContextAssumption()")
1499-
Shape doClassCached(@SuppressWarnings("unused") PythonClass clazz,
1503+
static Shape doClassCached(@SuppressWarnings("unused") PythonClass clazz,
15001504
@Cached("clazz") PythonClass cachedClazz) {
15011505
return cachedClazz.getInstanceShape();
15021506
}
15031507

15041508
@Specialization(replaces = {"doClassCached", "doBuiltinClassCached"})
1505-
Shape doManagedClass(PythonManagedClass clazz) {
1509+
static Shape doManagedClass(PythonManagedClass clazz) {
15061510
return clazz.getInstanceShape();
15071511
}
15081512

1513+
@Specialization
1514+
static Shape doNativeClass(@SuppressWarnings("unused") PythonAbstractNativeObject clazz,
1515+
@Shared("lang") @CachedLanguage PythonLanguage lang) {
1516+
return lang.getEmptyShape();
1517+
}
1518+
15091519
@Specialization(guards = {"!isManagedClass(clazz)", "!isPythonBuiltinClassType(clazz)"})
1510-
Shape doError(@SuppressWarnings("unused") Object clazz,
1520+
static Shape doError(@SuppressWarnings("unused") Object clazz,
15111521
@Cached PRaiseNode raise) {
15121522
throw raise.raise(PythonBuiltinClassType.SystemError, ErrorMessages.CANNOT_GET_SHAPE_OF_NATIVE_CLS);
15131523
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaLongNode.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ abstract class CastToJavaLongNode extends PNodeWithContext {
5757

5858
public abstract long execute(Object x) throws CannotCastException;
5959

60+
@Specialization
61+
static long doLong(byte x) {
62+
return x;
63+
}
64+
6065
@Specialization
6166
static long doLong(int x) {
6267
return x;

0 commit comments

Comments
 (0)