Skip to content

Commit 0d7f039

Browse files
committed
define _PyList_SET_ITEM to map PyList_SET_ITEM macro behaviour
1 parent 2d97622 commit 0d7f039

File tree

9 files changed

+111
-6
lines changed

9 files changed

+111
-6
lines changed

graalpython/com.oracle.graal.python.cext/include/cpython/listobject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@ PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out);
3535
#define _PyList_CAST(op) (assert(PyList_Check(op)), (PyListObject *)(op))
3636

3737
#define PyList_GET_ITEM(op, i) (PyList_GetItem((PyObject *)(op), (i)))
38-
#define PyList_SET_ITEM(op, i, v) (PyList_SetItem((PyObject *)(op), (i), (v)))
38+
PyAPI_FUNC(void) _PyList_SET_ITEM(PyObject *, Py_ssize_t, PyObject *);
39+
#define PyList_SET_ITEM(op, i, v) (_PyList_SET_ITEM((PyObject *)(op), (i), (v)))
3940
#define PyList_GET_SIZE(op) Py_SIZE(_PyList_CAST(op))

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,10 @@ PyAPI_FUNC(void) _PyErr_WriteUnraisableMsg(const char* a, PyObject* b) {
23972397
PyAPI_FUNC(PyObject*) _PyList_Extend(PyListObject* a, PyObject* b) {
23982398
return Graal_PyList_Extend(a, b);
23992399
}
2400+
#undef _PyList_SET_ITEM
2401+
PyAPI_FUNC(void) _PyList_SET_ITEM(PyObject* a, Py_ssize_t b, PyObject* c) {
2402+
Graal_PyList_SET_ITEM(a, b, c);
2403+
}
24002404
#undef _PyLong_Sign
24012405
PyAPI_FUNC(int) _PyLong_Sign(PyObject* a) {
24022406
return Graal_PyLong_Sign(a);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ typedef struct {
607607
BUILTIN(_PyErr_BadInternalCall, void, const char*, int) \
608608
BUILTIN(_PyErr_WriteUnraisableMsg, void, const char*, PyObject*) \
609609
BUILTIN(_PyList_Extend, PyObject*, PyListObject*, PyObject*) \
610+
BUILTIN(_PyList_SET_ITEM, void, PyObject*, Py_ssize_t, PyObject*) \
610611
BUILTIN(_PyLong_Sign, int, PyObject*) \
611612
BUILTIN(_PyNamespace_New, PyObject*, PyObject*) \
612613
BUILTIN(_PyNumber_Index, PyObject*, PyObject*) \

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@
4040
*/
4141
#include "capi.h"
4242

43-
43+
void* PyTruffle_NativeListItems(PyListObject* list) {
44+
return polyglot_from_PyObjectPtr_array(list->ob_item, list->ob_base.ob_size);
45+
}

graalpython/com.oracle.graal.python.jni/src/capi_forwards.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,7 @@ void unimplemented(const char* name) {
13611361
#undef _PyInterpreterState_SetEvalFrameFunc
13621362
#undef _PyList_DebugMallocStats
13631363
#undef _PyList_Extend
1364+
#undef _PyList_SET_ITEM
13641365
#undef _PyLong_AsByteArray
13651366
#undef _PyLong_AsInt
13661367
#undef _PyLong_AsTime_t
@@ -5163,6 +5164,9 @@ PyAPI_FUNC(PyObject*) _PyList_Extend(PyListObject* a, PyObject* b) {
51635164
PyObject* result = (PyObject*) Graal_PyList_Extend(a, b);
51645165
return result;
51655166
}
5167+
PyAPI_FUNC(void) _PyList_SET_ITEM(PyObject* a, Py_ssize_t b, PyObject* c) {
5168+
Graal_PyList_SET_ITEM(a, b, c);
5169+
}
51665170
PyAPI_FUNC(time_t) _PyLong_AsTime_t(PyObject* a) {
51675171
unimplemented("_PyLong_AsTime_t"); exit(-1);
51685172
}

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
4242
__dir__ = __file__.rpartition("/")[0]
4343

44-
44+
4545
def _reference_new_list(args):
4646
n = args[0]
4747
if n < 0:
@@ -199,13 +199,26 @@ def compile_module(self, name):
199199
test_PyList_SET_ITEM = CPyExtFunction(
200200
_wrap_list_fun(_reference_SET_ITEM),
201201
lambda: (
202-
([1,2,3,4], 0, 0),
203-
([1,2,3,4], 3, 5),
202+
([1,2,3,4], 0, _reference_SET_ITEM),
203+
([1,2,3,4], 3, _reference_SET_ITEM),
204204
),
205205
code='''PyObject* wrap_PyList_SET_ITEM(PyObject* op, Py_ssize_t idx, PyObject* newitem) {
206206
Py_INCREF(newitem);
207207
PyList_SET_ITEM(op, idx, newitem);
208-
return op;
208+
int refcnt1 = Py_REFCNT(newitem);
209+
PyList_SET_ITEM(op, idx, Py_None);
210+
int refcnt2 = Py_REFCNT(newitem);
211+
PyList_SET_ITEM(op, idx, newitem);
212+
int refcnt3 = Py_REFCNT(newitem);
213+
// Important! PyList_SET_ITEM does not change the refcnts,
214+
// but PyList_SetItem decrefs the element that was
215+
// previously at idx. Let's make sure that semantic
216+
// difference is observed
217+
if (refcnt1 != refcnt2 || refcnt2 != refcnt3) {
218+
return Py_BuildValue("iii", refcnt1, refcnt2, refcnt3);
219+
} else {
220+
return op;
221+
}
209222
}
210223
''',
211224
resultspec="O",

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
4545
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
4646
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int;
47+
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Void;
4748
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyListObject;
4849
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObject;
4950
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectBorrowed;
@@ -61,10 +62,13 @@
6162
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
6263
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.PromoteBorrowedValue;
6364
import com.oracle.graal.python.builtins.objects.PNone;
65+
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
6466
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
6567
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.GetItemScalarNode;
6668
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ListGeneralizationNode;
69+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.SetItemNode;
6770
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.SetItemScalarNode;
71+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.GetItemScalarNodeGen;
6872
import com.oracle.graal.python.builtins.objects.list.ListBuiltins;
6973
import com.oracle.graal.python.builtins.objects.list.ListBuiltins.ListExtendNode;
7074
import com.oracle.graal.python.builtins.objects.list.ListBuiltins.ListInsertNode;
@@ -73,7 +77,9 @@
7377
import com.oracle.graal.python.lib.PySliceNew;
7478
import com.oracle.graal.python.nodes.ErrorMessages;
7579
import com.oracle.graal.python.nodes.builtins.ListNodes.AppendNode;
80+
import com.oracle.graal.python.nodes.builtins.ListNodes.GetNativeListStorage;
7681
import com.oracle.graal.python.nodes.builtins.TupleNodes.ConstructTupleNode;
82+
import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage;
7783
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
7884
import com.oracle.graal.python.util.PythonUtils;
7985
import com.oracle.truffle.api.dsl.Cached;
@@ -287,6 +293,49 @@ int fallback(Object list, @SuppressWarnings("unused") Object i, @SuppressWarning
287293
}
288294
}
289295

296+
@CApiBuiltin(ret = Void, args = {PyObject, Py_ssize_t, PyObject}, call = Direct)
297+
abstract static class _PyList_SET_ITEM extends CApiTernaryBuiltinNode {
298+
@Specialization
299+
int doManaged(PList list, long index, Object element,
300+
@Cached("createSetItem()") SequenceStorageNodes.SetItemNode setItemNode,
301+
@Cached ConditionProfile generalizedProfile) {
302+
SequenceStorage sequenceStorage = list.getSequenceStorage();
303+
checkBounds(sequenceStorage, index);
304+
SequenceStorage newStorage = setItemNode.execute(null, sequenceStorage, (int) index, element);
305+
if (generalizedProfile.profile(list.getSequenceStorage() != newStorage)) {
306+
list.setSequenceStorage(newStorage);
307+
}
308+
return 0;
309+
}
310+
311+
@Specialization
312+
int doNative(PythonAbstractNativeObject list, long index, Object element,
313+
@Cached GetNativeListStorage asNativeStorage,
314+
@Cached SequenceStorageNodes.InitializeNativeItemScalarNode setItemNode) {
315+
NativeSequenceStorage sequenceStorage = asNativeStorage.execute(list);
316+
checkBounds(sequenceStorage, index);
317+
setItemNode.execute(sequenceStorage, (int) index, element);
318+
return 0;
319+
}
320+
321+
@Fallback
322+
@SuppressWarnings("unused")
323+
Object fallback(Object list, Object index, Object element) {
324+
throw raiseFallback(list, PythonBuiltinClassType.PList);
325+
}
326+
327+
private void checkBounds(SequenceStorage sequenceStorage, long index) {
328+
// we must do a bounds-check but we must not normalize the index
329+
if (index < 0 || index >= sequenceStorage.length()) {
330+
throw raise(IndexError, ErrorMessages.INDEX_OUT_OF_BOUNDS);
331+
}
332+
}
333+
334+
protected static SetItemNode createSetItem() {
335+
return SetItemNode.create(null, ListGeneralizationNode::create);
336+
}
337+
}
338+
290339
@CApiBuiltin(ret = Int, args = {PyObject}, call = Direct)
291340
abstract static class PyList_Reverse extends CApiUnaryBuiltinNode {
292341
@Specialization

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
@@ -218,6 +218,7 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
218218
FUN_PY_TRUFFLE_OBJECT_ARRAY_FREE("PyTruffle_ObjectArrayFree"),
219219
FUN_PY_TRUFFLE_SET_STORAGE_ITEM("PyTruffle_SetStorageItem"),
220220
FUN_PY_TRUFFLE_INITIALIZE_STORAGE_ITEM("PyTruffle_InitializeStorageItem"),
221+
FUN_PY_TRUFFLE_NATIVE_LIST_ITEMS("PyTruffle_NativeListItems"),
221222
FUN_PY_TRUFFLE_NATIVE_TUPLE_ITEMS("PyTruffle_NativeTupleItems"),
222223
FUN_PY_TRUFFLE_NATIVE_BYTES_ITEMS("PyTruffle_NativeBytesItems"),
223224
FUN_PY_OBJECT_GENERIC_GET_DICT("_PyObject_GenericGetDict"),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/ListNodes.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4949
import com.oracle.graal.python.builtins.modules.MathGuards;
5050
import com.oracle.graal.python.builtins.objects.PNone;
51+
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
52+
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.PCallCapiFunction;
53+
import com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol;
5154
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
5255
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
5356
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ListGeneralizationNode;
@@ -66,19 +69,24 @@
6669
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.ConstructListNodeGen;
6770
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.IndexNodeGen;
6871
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
72+
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
6973
import com.oracle.graal.python.nodes.object.GetClassNode;
74+
import com.oracle.graal.python.nodes.object.InlinedGetClassNode;
7075
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
7176
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
7277
import com.oracle.graal.python.runtime.PythonOptions;
7378
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
7479
import com.oracle.graal.python.runtime.sequence.PSequence;
7580
import com.oracle.graal.python.runtime.sequence.storage.BasicSequenceStorage;
81+
import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage;
7682
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
83+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage.ListStorageType;
7784
import com.oracle.truffle.api.CompilerDirectives;
7885
import com.oracle.truffle.api.dsl.Bind;
7986
import com.oracle.truffle.api.dsl.Cached;
8087
import com.oracle.truffle.api.dsl.Cached.Shared;
8188
import com.oracle.truffle.api.dsl.Fallback;
89+
import com.oracle.truffle.api.dsl.GenerateInline;
8290
import com.oracle.truffle.api.dsl.GenerateUncached;
8391
import com.oracle.truffle.api.dsl.Idempotent;
8492
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -87,6 +95,9 @@
8795
import com.oracle.truffle.api.dsl.TypeSystemReference;
8896
import com.oracle.truffle.api.frame.Frame;
8997
import com.oracle.truffle.api.frame.VirtualFrame;
98+
import com.oracle.truffle.api.interop.InteropLibrary;
99+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
100+
import com.oracle.truffle.api.library.CachedLibrary;
90101
import com.oracle.truffle.api.nodes.Node;
91102
import com.oracle.truffle.api.profiles.BranchProfile;
92103
import com.oracle.truffle.api.strings.TruffleString;
@@ -346,4 +357,23 @@ public static AppendNode getUncached() {
346357
return AppendNodeGen.getUncached();
347358
}
348359
}
360+
361+
@GenerateInline(false)
362+
public abstract static class GetNativeListStorage extends Node {
363+
public abstract NativeSequenceStorage execute(PythonAbstractNativeObject list);
364+
365+
@Specialization
366+
NativeSequenceStorage getNative(PythonAbstractNativeObject list,
367+
@CachedLibrary(limit = "1") InteropLibrary lib,
368+
@Cached PCallCapiFunction callCapiFunction) {
369+
assert IsSubtypeNode.getUncached().execute(InlinedGetClassNode.executeUncached(list), PythonBuiltinClassType.PList);
370+
try {
371+
Object interopArray = callCapiFunction.call(NativeCAPISymbol.FUN_PY_TRUFFLE_NATIVE_LIST_ITEMS, list.getPtr());
372+
int size = (int) lib.getArraySize(interopArray);
373+
return NativeSequenceStorage.create(interopArray, size, size, ListStorageType.Generic, false);
374+
} catch (UnsupportedMessageException e) {
375+
throw CompilerDirectives.shouldNotReachHere(e);
376+
}
377+
}
378+
}
349379
}

0 commit comments

Comments
 (0)