Skip to content

Commit 2cf0e08

Browse files
committed
implemented downcall for native objects in PyObject_Size
1 parent 1c2b072 commit 2cf0e08

File tree

5 files changed

+130
-46
lines changed

5 files changed

+130
-46
lines changed

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ Py_ssize_t PySequence_Size(PyObject *s) {
292292

293293
// PySequence_Size downcall for native python objects
294294
// taken from CPython "Objects/abstract.c/Py_Sequence_Size"
295-
Py_ssize_t PyTruffle_Sequence_Size(PyObject *s) {
295+
Py_ssize_t PyTruffle_PySequence_Size(PyObject *s) {
296296
PySequenceMethods *m;
297297

298298
if (s == NULL) {
@@ -372,10 +372,31 @@ PyObject * PyMapping_GetItemString(PyObject *o, const char *key) {
372372
return _jls_PyObject_GetItem(native_to_java(o), polyglot_from_string(key, SRC_CS));
373373
}
374374

375+
UPCALL_ID(PyObject_Size);
375376
Py_ssize_t PyObject_Size(PyObject *o) {
376377
return UPCALL_CEXT_L(_jls_PyObject_Size, native_to_java(o));
377378
}
378379

380+
// PyObject_Size downcall for native python objects
381+
// taken from CPython "Objects/abstract.c/Py_Object_Size"
382+
Py_ssize_t PyTruffle_PyObject_Size(PyObject *o) {
383+
PySequenceMethods *m;
384+
385+
if (o == NULL) {
386+
null_error();
387+
return -1;
388+
}
389+
390+
m = o->ob_type->tp_as_sequence;
391+
if (m && m->sq_length) {
392+
Py_ssize_t len = m->sq_length(o);
393+
assert(len >= 0 || PyErr_Occurred());
394+
return len;
395+
}
396+
397+
return PyMapping_Size(o);
398+
}
399+
379400
UPCALL_ID(PyMapping_Keys);
380401
PyObject * PyMapping_Keys(PyObject *o) {
381402
return UPCALL_CEXT_O(_jls_PyMapping_Keys, native_to_java(o));
@@ -553,7 +574,7 @@ Py_ssize_t PyMapping_Size(PyObject *s) {
553574

554575
// PyMapping_Size downcall for native python objects
555576
// partially taken from CPython "Objects/abstract.c/Py_Mapping_Size"
556-
Py_ssize_t PyTruffle_Mapping_Size(PyObject *o) {
577+
Py_ssize_t PyTruffle_PyMapping_Size(PyObject *o) {
557578
PyMappingMethods *m;
558579

559580
if (o == NULL) {

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

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,47 @@ def _reference_next(args):
107107

108108
def _reference_seq_size(args):
109109
seq = args[0]
110-
# XXX check
111-
if isinstance(seq, dict) or isinstance(seq, type(type.__dict__)) or isinstance(seq, set) or isinstance(seq, frozenset) or not hasattr(seq, '__len__'):
112-
if sys.version_info.minor >= 6:
113-
raise SystemError
114-
else:
115-
raise TypeError
116-
return len(seq)
110+
if can_be_seq(seq):
111+
return len(seq)
112+
if sys.version_info.minor >= 6:
113+
raise SystemError
114+
else:
115+
raise TypeError
117116

118117
def _reference_mapping_size(args):
119118
m = args[0]
120-
if not (isinstance(m, dict) or isinstance(m, type(type.__dict__))) or not hasattr(m, '__getitem__'):
121-
if sys.version_info.minor >= 6:
122-
raise SystemError
123-
else:
124-
raise TypeError
125-
return len(m)
119+
if can_be_mapping(m):
120+
return len(m)
121+
if sys.version_info.minor >= 6:
122+
raise SystemError
123+
else:
124+
raise TypeError
125+
126+
def _reference_object_size(args):
127+
o = args[0]
128+
if can_be_seq(o) or can_be_mapping(o):
129+
return len(o)
130+
if sys.version_info.minor >= 6:
131+
raise SystemError
132+
else:
133+
raise TypeError()
134+
135+
def can_be_seq(obj):
136+
# XXX check seq/frozenseq
137+
if isinstanceof(obj, [dict, type(type.__dict__), set, frozenset]):
138+
return False
139+
return hasattr(obj, '__getitem__')
140+
141+
def can_be_mapping(obj):
142+
if isinstanceof(obj, [str, bytes, list, tuple, set, frozenset, memoryview, range]):
143+
return False
144+
return hasattr(obj, '__getitem__')
145+
146+
def isinstanceof(obj, types):
147+
for t in types:
148+
if isinstance(obj, t):
149+
return True
150+
return False
126151

127152
def _reference_getitem(args):
128153
seq = args[0]
@@ -195,8 +220,10 @@ def __float__(self):
195220
class DummySequence():
196221

197222
def __getitem__(self, idx):
198-
return idx * 10
199-
223+
raise IndexError
224+
225+
def __len__(self):
226+
return 0
200227

201228
class DummyListSubclass(list):
202229
pass
@@ -774,6 +801,7 @@ def compile_module(self, name):
774801
([None],),
775802
(set(),),
776803
(frozenset(),),
804+
(DummySequence(),),
777805
(DummyListSubclass(),),
778806
('hello',),
779807
({},),
@@ -981,6 +1009,7 @@ def compile_module(self, name):
9811009
([None],),
9821010
(set(),),
9831011
(frozenset(),),
1012+
(DummySequence(),),
9841013
(DummyListSubclass(),),
9851014
('hello',),
9861015
({},),
@@ -1097,3 +1126,31 @@ def compile_module(self, name):
10971126
arguments=["PyObject* s", "PyObject* o"],
10981127
cmpfunc=unhandled_error_compare
10991128
)
1129+
1130+
test_PyObject_Size = CPyExtFunction(
1131+
_reference_object_size,
1132+
lambda: (
1133+
(tuple(),),
1134+
((1, 2, 3),),
1135+
((None,),),
1136+
([],),
1137+
(['a', 'b', 'c'],),
1138+
([None],),
1139+
(set(),),
1140+
(frozenset(),),
1141+
(DummySequence(),),
1142+
(DummyListSubclass(),),
1143+
('hello',),
1144+
({},),
1145+
({1, 1},),
1146+
(type.__dict__,), #mappingproxy
1147+
(NoNumber(),),
1148+
(sys.modules, ),
1149+
),
1150+
resultspec="n",
1151+
argspec='O',
1152+
arguments=["PyObject* obj"],
1153+
cmpfunc=unhandled_error_compare
1154+
)
1155+
1156+
test_PyObject_Length = test_PyObject_Size

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,7 @@ def is_buffer(x):
9090
# PyObject_Del
9191
# PyObject_FREE
9292
# PyObject_Free
93-
def forgiving_len(o):
94-
try:
95-
return len(o)
96-
except TypeError:
97-
return -1
9893

99-
test_PyObject_Length = CPyExtFunction(
100-
forgiving_len,
101-
lambda: ([], [1, 2, 3, 4], (1,), sys.modules),
102-
resultspec="i",
103-
)
104-
test_PyObject_Size = CPyExtFunction(
105-
forgiving_len,
106-
lambda: ([], [1, 2, 3, 4], (1,), {1:1}, sys.modules),
107-
resultspec="i",
108-
)
10994
# PyObject_MALLOC
11095
# PyObject_Malloc
11196
# PyObject_New

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules.cext;
4242

43-
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_MAPPING_SIZE;
44-
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_SEQUENCE_SIZE;
43+
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_PY_MAPPING_SIZE;
44+
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_PY_OBJECT_SIZE;
45+
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_PY_SEQUENCE_SIZE;
4546
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
4647
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4748
import static com.oracle.graal.python.nodes.ErrorMessages.BASE_MUST_BE;
@@ -993,8 +994,8 @@ static Object doNative(VirtualFrame frame, Object obj,
993994
@Cached AsPythonObjectNode asPythonObjectNode,
994995
@Cached PCallCapiFunction callCapiFunction,
995996
@Cached DefaultCheckFunctionResultNode checkFunctionResultNode) {
996-
Object result = callCapiFunction.call(FUN_PY_TRUFFLE_SEQUENCE_SIZE, toSulongNode.execute(obj));
997-
checkFunctionResultNode.execute(PythonContext.get(callCapiFunction), FUN_PY_TRUFFLE_SEQUENCE_SIZE.getName(), result);
997+
Object result = callCapiFunction.call(FUN_PY_TRUFFLE_PY_SEQUENCE_SIZE, toSulongNode.execute(obj));
998+
checkFunctionResultNode.execute(PythonContext.get(callCapiFunction), FUN_PY_TRUFFLE_PY_SEQUENCE_SIZE.getName(), result);
998999
return asPythonObjectNode.execute(result);
9991000
}
10001001

@@ -1074,6 +1075,23 @@ static Object doGenericUnboxed(VirtualFrame frame, Object obj,
10741075
protected static boolean isMappingOrSequence(Object obj) {
10751076
return obj instanceof PSequence || obj instanceof PHashingCollection;
10761077
}
1078+
1079+
@Specialization(guards = {"isNativeObject(obj)"})
1080+
static Object size(VirtualFrame frame, Object obj,
1081+
@Cached ToSulongNode toSulongNode,
1082+
@Cached AsPythonObjectNode asPythonObjectNode,
1083+
@Cached PCallCapiFunction callCapiFunction,
1084+
@Cached DefaultCheckFunctionResultNode checkFunctionResultNode) {
1085+
Object result = callCapiFunction.call(FUN_PY_TRUFFLE_PY_OBJECT_SIZE, toSulongNode.execute(obj));
1086+
checkFunctionResultNode.execute(PythonContext.get(callCapiFunction), FUN_PY_TRUFFLE_PY_OBJECT_SIZE.getName(), result);
1087+
return asPythonObjectNode.execute(result);
1088+
}
1089+
1090+
@Specialization(guards = {"!isNativeObject(obj)", "!isMappingOrSequence(obj)"})
1091+
static Object size(VirtualFrame frame, Object obj,
1092+
@Cached PRaiseNativeNode raiseNativeNode) {
1093+
return raiseNativeNode.raiseInt(frame, -1, TypeError, ErrorMessages.OBJ_HAS_NO_LEN, obj);
1094+
}
10771095
}
10781096

10791097
/////// PyMapping ///////
@@ -1184,9 +1202,8 @@ public Object values(VirtualFrame frame, Object obj,
11841202
@ImportStatic(SpecialMethodNames.class)
11851203
abstract static class PyMappingSizeNode extends PythonUnaryBuiltinNode {
11861204

1187-
@Specialization(guards = "checkNode.execute(obj)")
1188-
static int doSequence(VirtualFrame frame, Object obj,
1189-
@SuppressWarnings("unused") @Cached PyMappingCheckNode checkNode,
1205+
@Specialization
1206+
static int doSequence(VirtualFrame frame, PHashingCollection obj,
11901207
@Cached PyObjectSizeNode sizeNode,
11911208
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
11921209
try {
@@ -1203,17 +1220,20 @@ static Object doNative(VirtualFrame frame, Object obj,
12031220
@Cached AsPythonObjectNode asPythonObjectNode,
12041221
@Cached PCallCapiFunction callCapiFunction,
12051222
@Cached DefaultCheckFunctionResultNode checkFunctionResultNode) {
1206-
Object result = callCapiFunction.call(FUN_PY_TRUFFLE_MAPPING_SIZE, toSulongNode.execute(obj));
1207-
checkFunctionResultNode.execute(PythonContext.get(callCapiFunction), FUN_PY_TRUFFLE_MAPPING_SIZE.getName(), result);
1223+
Object result = callCapiFunction.call(FUN_PY_TRUFFLE_PY_MAPPING_SIZE, toSulongNode.execute(obj));
1224+
checkFunctionResultNode.execute(PythonContext.get(callCapiFunction), FUN_PY_TRUFFLE_PY_MAPPING_SIZE.getName(), result);
12081225
return asPythonObjectNode.execute(result);
12091226
}
12101227

1211-
@Specialization(guards = {"!isNativeObject(obj)", "!checkNode.execute(obj)"})
1228+
@Specialization(guards = {"!isNativeObject(obj)", "!isMapping(obj)"})
12121229
Object notSequence(VirtualFrame frame, Object obj,
1213-
@SuppressWarnings("unused") @Cached PyMappingCheckNode checkNode,
12141230
@Cached PRaiseNativeNode raiseNativeNode) {
12151231
return raiseNativeNode.raiseInt(frame, -1, TypeError, OBJ_ISNT_MAPPING, obj);
12161232
}
1233+
1234+
protected boolean isMapping(Object obj) {
1235+
return obj instanceof PHashingCollection;
1236+
}
12171237
}
12181238

12191239
/////// PyIter ///////

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -164,11 +164,12 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
164164
FUN_GET_LONG_BITS_PER_DIGIT("get_long_bits_in_digit"),
165165
FUN_BULK_SUBREF("PyTruffle_bulk_SUBREF"),
166166
FUN_TRUFFLE_ADD_SUBOFFSET("truffle_add_suboffset"),
167-
FUN_PY_TRUFFLE_MAPPING_SIZE("PyTruffle_Mapping_Size"),
167+
FUN_PY_TRUFFLE_PY_MAPPING_SIZE("PyTruffle_PyMapping_Size"),
168168
FUN_PY_TRUFFLE_MEMORYVIEW_FROM_BUFFER("PyTruffle_MemoryViewFromBuffer"),
169169
FUN_PY_TRUFFLE_MEMORYVIEW_FROM_OBJECT("PyTruffle_MemoryViewFromObject"),
170+
FUN_PY_TRUFFLE_PY_OBJECT_SIZE("PyTruffle_PyObject_Size"),
170171
FUN_PY_TRUFFLE_RELEASE_BUFFER("PyTruffle_ReleaseBuffer"),
171-
FUN_PY_TRUFFLE_SEQUENCE_SIZE("PyTruffle_Sequence_Size"),
172+
FUN_PY_TRUFFLE_PY_SEQUENCE_SIZE("PyTruffle_PySequence_Size"),
172173
FUN_GET_INT_T_TYPEID("get_int_t_typeid"),
173174
FUN_GET_INT8_T_TYPEID("get_int8_t_typeid"),
174175
FUN_GET_INT16_T_TYPEID("get_int16_t_typeid"),

0 commit comments

Comments
 (0)