Skip to content

Commit 03613ea

Browse files
committed
[GR-34916] Intrinsify python_cext - PyObject_XXX.
PullRequest: graalpython/2104
2 parents d9de178 + 7366711 commit 03613ea

File tree

9 files changed

+758
-443
lines changed

9 files changed

+758
-443
lines changed

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

Lines changed: 5 additions & 1 deletion
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
@@ -347,6 +347,10 @@ PyObject * PyMapping_GetItemString(PyObject *o, const char *key) {
347347
return _jls_PyObject_GetItem(native_to_java(o), polyglot_from_string(key, SRC_CS));
348348
}
349349

350+
Py_ssize_t PyObject_Size(PyObject *o) {
351+
return UPCALL_CEXT_L(_jls_PyObject_Size, native_to_java(o));
352+
}
353+
350354
UPCALL_ID(PyMapping_Keys);
351355
PyObject * PyMapping_Keys(PyObject *o) {
352356
return UPCALL_CEXT_O(_jls_PyMapping_Keys, native_to_java(o));

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

Lines changed: 1 addition & 6 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
@@ -135,11 +135,6 @@ int PyObject_GenericInit(PyObject* self, PyObject* args, PyObject* kwds) {
135135
return self;
136136
}
137137

138-
UPCALL_ID(PyObject_Size);
139-
Py_ssize_t PyObject_Size(PyObject *o) {
140-
return UPCALL_CEXT_L(_jls_PyObject_Size, native_to_java(o));
141-
}
142-
143138
typedef void (*object_dump_fun_t)(PyObject *);
144139
UPCALL_TYPED_ID(_PyObject_Dump, object_dump_fun_t);
145140
void _PyObject_Dump(PyObject* op) {

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

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -103,7 +103,7 @@ def forgiving_len(o):
103103
)
104104
test_PyObject_Size = CPyExtFunction(
105105
forgiving_len,
106-
lambda: ([], [1, 2, 3, 4], (1,), sys.modules),
106+
lambda: ([], [1, 2, 3, 4], (1,), {1:1}, sys.modules),
107107
resultspec="i",
108108
)
109109
# PyObject_MALLOC
@@ -130,7 +130,7 @@ def forgiving_len(o):
130130
(kwonly_fun, tuple(), {"x": 456, "y": 789}),
131131
(sum, ("hello, world",), None),
132132
(kwonly_fun, tuple(), None),
133-
)
133+
)
134134

135135
test_PyObject_Call = CPyExtFunction(
136136
lambda args: args[0](*args[1], **args[2]) if args[2] else args[0](*args[1], **dict()),
@@ -324,36 +324,53 @@ def forgiving_set_item(args):
324324
lambda: ([], {}, 0, 123, b"ello")
325325
)
326326

327-
# richcompare_args = ([ ([], [], i) for i in range(6) ] +
328-
# [ (12, 24, i) for i in range(6) ] +
329-
# [ ("aa", "ba", i) for i in range(6) ])
330-
331-
# def richcompare(args):
332-
# return eval("%r %s %r" % (args[0], ["<", "<=", "==", "!=", ">", ">="][args[2]], args[1]))
327+
richcompare_args = lambda: (([], [], 0),
328+
([], [], 1),
329+
([], [], 2),
330+
([], [], 3),
331+
([], [], 4),
332+
([], [], 5),
333+
(12, 24, 0),
334+
(12, 24, 1),
335+
(12, 24, 2),
336+
(12, 24, 3),
337+
(12, 24, 4),
338+
(12, 24, 5),
339+
("aa", "ba", 0),
340+
("aa", "ba", 1),
341+
("aa", "ba", 2),
342+
("aa", "ba", 3),
343+
("aa", "ba", 4),
344+
("aa", "ba", 5))
345+
346+
def richcompare(args):
347+
return eval("%r %s %r" % (args[0], ["<", "<=", "==", "!=", ">", ">="][args[2]], args[1]))
348+
349+
test_PyObject_RichCompare = CPyExtFunction(
350+
richcompare,
351+
richcompare_args,
352+
arguments=["PyObject* left", "PyObject* right", "int op"],
353+
argspec="OOi",
354+
resultspec="O",
355+
)
333356

334-
# test_PyObject_RichCompare = CPyExtFunction(
335-
# richcompare,
336-
# richcompare_args,
337-
# arguments=["PyObject* left", "PyObject* right", "int op"],
338-
# argspec="OOi",
339-
# )
357+
def richcompare_bool(args):
358+
try:
359+
if eval("%r %s %r" % (args[0], ["<", "<=", "==", "!=", ">", ">="][args[2]], args[1])):
360+
return 1
361+
else:
362+
return 0
363+
except:
364+
return -1
340365

341-
# def richcompare_bool(args):
342-
# try:
343-
# if eval("%r %s %r" % (args[0], ["<", "<=", "==", "!=", ">", ">="][args[2]], args[1])):
344-
# return 1
345-
# else:
346-
# return 0
347-
# except:
348-
# return -1
349-
350-
# test_PyObject_RichCompareBool = CPyExtFunction(
351-
# richcompare_bool,
352-
# richcompare_args,
353-
# arguments=["PyObject* left", "PyObject* right", "int op"],
354-
# argspec="OOi",
355-
# resultspec="i",
356-
# )
366+
test_PyObject_RichCompareBool = CPyExtFunction(
367+
richcompare_bool,
368+
richcompare_args,
369+
arguments=["PyObject* left", "PyObject* right", "int op"],
370+
argspec="OOi",
371+
resultspec="i",
372+
)
373+
357374
__PyObject_GetAttrString_ARGS = (
358375
(MyObject(), "foo"),
359376
([], "__len__"),
@@ -386,6 +403,18 @@ def setattrstring(args):
386403
resultspec="i",
387404
cmpfunc=unhandled_error_compare
388405
)
406+
test_PyObject_HasAttr = CPyExtFunction(
407+
lambda args: 1 if hasattr(*args) else 0,
408+
lambda: (
409+
(TestPyObject.MyObject, "foo"),
410+
([], "__len__"),
411+
([], "foobar"),
412+
),
413+
arguments=["PyObject* object", "PyObject* attr"],
414+
argspec="OO",
415+
resultspec="i",
416+
)
417+
389418
test_PyObject_HasAttrString = CPyExtFunction(
390419
lambda args: 1 if hasattr(*args) else 0,
391420
lambda: (
@@ -397,6 +426,23 @@ def setattrstring(args):
397426
argspec="Os",
398427
resultspec="i",
399428
)
429+
430+
def _ref_hash_not_implemented(args):
431+
if sys.version_info.minor >= 6:
432+
raise SystemError
433+
else:
434+
raise TypeError
435+
436+
test_PyObject_HashNotImplemented = CPyExtFunction(
437+
_ref_hash_not_implemented,
438+
lambda: (
439+
("foo",),
440+
),
441+
arguments=["PyObject* object"],
442+
argspec="O",
443+
resultspec="n",
444+
cmpfunc=unhandled_error_compare
445+
)
400446
__PyObject_GetAttr_ARGS = (
401447
(MyObject(), "foo"),
402448
([], "__len__"),

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -52,6 +52,7 @@ def _reference_bytes(args):
5252
res = obj.__bytes__()
5353
if not isinstance(res, bytes):
5454
raise TypeError("__bytes__ returned non-bytes (type %s)" % type(res).__name__)
55+
return res
5556
if isinstance(obj, (list, tuple, memoryview)) or (not isinstance(obj, str) and hasattr(obj, "__iter__")):
5657
return bytes(obj)
5758
raise TypeError("cannot convert '%s' object to bytes" % type(obj).__name__)
@@ -683,6 +684,16 @@ def test_doc(self):
683684
assert len(obj.some_member.__doc__) == len(expected_doc)
684685
assert obj.some_member.__doc__ == expected_doc
685686

687+
class CBytes:
688+
def __bytes__(self):
689+
return b'abc'
690+
691+
class CBytesWrongReturn:
692+
def __bytes__(self):
693+
return 'abc'
694+
695+
class DummyBytes(bytes):
696+
pass
686697

687698
class TestObjectFunctions(CPyExtTestCase):
688699
def compile_module(self, name):
@@ -712,6 +723,10 @@ def compile_module(self, name):
712723
(memoryview(b"world"),),
713724
(1.234,),
714725
(bytearray(b"blah"),),
726+
(CBytes(),),
727+
(CBytesWrongReturn(),),
728+
(DummyBytes(),),
729+
([1,2,3],),
715730
),
716731
arguments=["PyObject* obj"],
717732
resultspec="O",

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
import com.oracle.graal.python.builtins.modules.cext.PythonCextIterBuiltins;
125125
import com.oracle.graal.python.builtins.modules.cext.PythonCextModuleBuiltins;
126126
import com.oracle.graal.python.builtins.modules.cext.PythonCextNamespaceBuiltins;
127+
import com.oracle.graal.python.builtins.modules.cext.PythonCextObjectBuiltins;
127128
import com.oracle.graal.python.builtins.modules.cext.PythonCextPythonRunBuiltins;
128129
import com.oracle.graal.python.builtins.modules.cext.PythonCextSetBuiltins;
129130
import com.oracle.graal.python.builtins.modules.cext.PythonCextUnicodeBuiltins;
@@ -498,6 +499,7 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
498499
new PythonCextLongBuiltins(),
499500
new PythonCextMemoryViewBuiltins(),
500501
new PythonCextModuleBuiltins(),
502+
new PythonCextObjectBuiltins(),
501503
new PythonCextPythonRunBuiltins(),
502504
new PythonCextNamespaceBuiltins(),
503505
new PythonCextSetBuiltins(),

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,17 @@
6969
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.NativeBuiltin;
7070
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.PyErrRestoreNode;
7171
import com.oracle.graal.python.builtins.objects.PNone;
72+
import com.oracle.graal.python.builtins.objects.cext.PythonNativeVoidPtr;
73+
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes;
7274
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.AddRefCntNode;
7375
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.AsPythonObjectNode;
7476
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.PRaiseNativeNode;
7577
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.ToNewRefNode;
7678
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.TransformExceptionToNativeNode;
7779
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper.PrimitiveNativeWrapper;
80+
import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes;
81+
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
82+
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
7883
import com.oracle.graal.python.builtins.objects.dict.DictBuiltins.ItemsNode;
7984
import com.oracle.graal.python.builtins.objects.dict.DictBuiltins.KeysNode;
8085
import com.oracle.graal.python.builtins.objects.dict.DictBuiltins.ValuesNode;
@@ -87,8 +92,10 @@
8792
import com.oracle.graal.python.lib.PyObjectLookupAttr;
8893
import com.oracle.graal.python.lib.PySequenceCheckNode;
8994
import com.oracle.graal.python.nodes.ErrorMessages;
95+
import com.oracle.graal.python.nodes.SpecialMethodNames;
9096
import com.oracle.graal.python.nodes.builtins.ListNodes.ConstructListNode;
9197
import com.oracle.graal.python.nodes.call.CallNode;
98+
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
9299
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
93100
import com.oracle.graal.python.nodes.expression.BinaryArithmetic.MulNode;
94101
import com.oracle.graal.python.nodes.expression.BinaryOpNode;
@@ -106,10 +113,12 @@
106113
import com.oracle.graal.python.nodes.subscript.SliceLiteralNode;
107114
import com.oracle.graal.python.nodes.truffle.PythonTypes;
108115
import com.oracle.graal.python.runtime.exception.PException;
116+
import com.oracle.graal.python.runtime.sequence.PSequence;
109117
import com.oracle.truffle.api.CompilerDirectives;
110118
import com.oracle.truffle.api.dsl.Cached;
111119
import com.oracle.truffle.api.dsl.Fallback;
112120
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
121+
import com.oracle.truffle.api.dsl.ImportStatic;
113122
import com.oracle.truffle.api.dsl.NodeFactory;
114123
import com.oracle.truffle.api.dsl.Specialization;
115124
import com.oracle.truffle.api.dsl.TypeSystemReference;
@@ -976,6 +985,53 @@ Object doManaged(VirtualFrame frame, Object listWrapper, Object key,
976985
}
977986
}
978987

988+
@Builtin(name = "PyObject_Size", minNumOfPositionalArgs = 1)
989+
@GenerateNodeFactory
990+
@ImportStatic(SpecialMethodNames.class)
991+
abstract static class PyObject_Size extends PythonUnaryBuiltinNode {
992+
993+
// n.b.: specializations 'doSequence' and 'doMapping' are not just shortcuts but also
994+
// required for correctness because CPython's implementation uses
995+
// 'type->tp_as_sequence->sq_length', 'type->tp_as_mapping->mp_length' which will bypass
996+
// any
997+
// user implementation of '__len__'.
998+
@Specialization
999+
static int doSequence(PSequence sequence,
1000+
@Cached SequenceNodes.LenNode seqLenNode) {
1001+
return seqLenNode.execute(sequence);
1002+
}
1003+
1004+
@Specialization
1005+
static int doMapping(PHashingCollection container,
1006+
@Cached HashingCollectionNodes.LenNode seqLenNode) {
1007+
return seqLenNode.execute(container);
1008+
}
1009+
1010+
@Specialization(guards = "!isMappingOrSequence(obj)")
1011+
static Object doGenericUnboxed(VirtualFrame frame, Object obj,
1012+
@Cached("create(Len)") LookupAndCallUnaryNode callLenNode,
1013+
@Cached ConditionProfile noLenProfile,
1014+
@Cached CExtNodes.CastToNativeLongNode castToLongNode,
1015+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
1016+
try {
1017+
Object result = callLenNode.executeObject(frame, obj);
1018+
if (noLenProfile.profile(result == PNone.NO_VALUE)) {
1019+
return -1;
1020+
}
1021+
Object lresult = castToLongNode.execute(result);
1022+
assert lresult instanceof Long || lresult instanceof PythonNativeVoidPtr;
1023+
return lresult;
1024+
} catch (PException e) {
1025+
transformExceptionToNativeNode.execute(frame, e);
1026+
return -1;
1027+
}
1028+
}
1029+
1030+
protected static boolean isMappingOrSequence(Object obj) {
1031+
return obj instanceof PSequence || obj instanceof PHashingCollection;
1032+
}
1033+
}
1034+
9791035
/////// PyMapping ///////
9801036

9811037
@Builtin(name = "PyMapping_Keys", minNumOfPositionalArgs = 1)

0 commit comments

Comments
 (0)