Skip to content

Commit 39172ad

Browse files
committed
HPy slots can be backed off by TpSlots
1 parent cac7160 commit 39172ad

File tree

13 files changed

+500
-239
lines changed

13 files changed

+500
-239
lines changed

graalpython/com.oracle.graal.python.hpy.test/src/hpytest/test_slots.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# MIT License
22
#
3-
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
3+
# Copyright (c) 2020, 2024, Oracle and/or its affiliates.
44
# Copyright (c) 2019 pyhandle
55
#
66
# Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -633,7 +633,10 @@ def test_sq_item_and_sq_length(self):
633633
assert len(p) == 1234
634634
assert p[4] == 8
635635
assert p[21] == 42
636-
assert p[-1] == 1233 * 2
636+
assert p[-1] == 1233 * 2, str(p[-1])
637+
assert p.__getitem__(4) == 8
638+
assert p.__getitem__(21) == 42
639+
assert p.__getitem__(-1) == 1233 * 2
637640

638641
def test_sq_ass_item(self):
639642
import pytest

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/objects/TpSlotsTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void testBuilderBasic() {
6060
for (TpSlotMeta def : TpSlotMeta.VALUES) {
6161
// Use the TpSlotMeta as dummy "callable" object to verify that the slot values were
6262
// properly assigned to the right fields of TpSlots record
63-
builder.set(def, new TpSlotNative(def));
63+
builder.set(def, TpSlotNative.createCExtSlot(def));
6464
}
6565

6666
TpSlots slots = builder.build();
@@ -75,9 +75,9 @@ public void testBuilderBasic() {
7575
@Test
7676
public void testBuilderOptimizations1() {
7777
Builder builder = TpSlots.newBuilder();
78-
builder.set(TpSlotMeta.MP_LENGTH, new TpSlotNative(TpSlotMeta.MP_LENGTH));
79-
builder.set(TpSlotMeta.TP_GETATTR, new TpSlotNative(TpSlotMeta.TP_GETATTR));
80-
builder.set(TpSlotMeta.TP_SETATTR, new TpSlotNative(TpSlotMeta.TP_SETATTR));
78+
builder.set(TpSlotMeta.MP_LENGTH, TpSlotNative.createCExtSlot(TpSlotMeta.MP_LENGTH));
79+
builder.set(TpSlotMeta.TP_GETATTR, TpSlotNative.createCExtSlot(TpSlotMeta.TP_GETATTR));
80+
builder.set(TpSlotMeta.TP_SETATTR, TpSlotNative.createCExtSlot(TpSlotMeta.TP_SETATTR));
8181

8282
TpSlots slots = builder.build();
8383
verifySlots(slots, def -> def == TpSlotMeta.MP_LENGTH || def == TpSlotMeta.TP_GETATTR || def == TpSlotMeta.TP_SETATTR);
@@ -91,7 +91,7 @@ public void testBuilderOptimizations1() {
9191
@Test
9292
public void testBuilderOptimizations2() {
9393
Builder builder = TpSlots.newBuilder();
94-
builder.set(TpSlotMeta.SQ_LENGTH, new TpSlotNative(TpSlotMeta.SQ_LENGTH));
94+
builder.set(TpSlotMeta.SQ_LENGTH, TpSlotNative.createCExtSlot(TpSlotMeta.SQ_LENGTH));
9595

9696
TpSlots slots = builder.build();
9797
verifySlots(slots, def -> def == TpSlotMeta.SQ_LENGTH);

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

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,52 @@ def test_sq_len_and_item():
389389
''',
390390
sq_length="&my_sq_len",
391391
sq_item="my_sq_item")
392-
x = MySqLenItem()
393-
assert x[5] == 5
394-
assert x.__getitem__(5) == 5
395-
assert x[-1] == 9
396-
assert x.__getitem__(-1) == 9
397-
assert x[-20] == -10
398-
assert x.__getitem__(-20) == -10
392+
MySqItemAddDunderLen = CPyExtHeapType("MySqItemAddDunderLen",
393+
code = '''
394+
PyObject* my_sq_item(PyObject* self, Py_ssize_t index) { return PyLong_FromSsize_t(index); }
395+
''',
396+
slots=[
397+
'{Py_sq_item, &my_sq_item}',
398+
])
399+
MySqItemAddDunderLen.__len__ = lambda self: 10
400+
401+
def verify(x):
402+
assert x[5] == 5
403+
assert x.__getitem__(5) == 5
404+
assert x[-1] == 9
405+
assert x.__getitem__(-1) == 9
406+
assert x[-20] == -10
407+
assert x.__getitem__(-20) == -10
408+
409+
verify(MySqLenItem())
410+
verify(MySqItemAddDunderLen())
411+
412+
413+
def test_mp_len_and_sq_item():
414+
MyMpLenSqItem = CPyExtType("MyMpLenSqItem",
415+
'''
416+
Py_ssize_t my_mp_len(PyObject* a) { return 10; }
417+
PyObject* my_sq_item(PyObject* self, Py_ssize_t index) { return PyLong_FromSsize_t(index); }
418+
''',
419+
mp_length="&my_mp_len",
420+
sq_item="my_sq_item")
421+
MyMpLenSqItemHeap = CPyExtHeapType("MyMpLenSqItemHeap",
422+
code = '''
423+
Py_ssize_t my_mp_len(PyObject* a) { return 10; }
424+
PyObject* my_sq_item(PyObject* self, Py_ssize_t index) { return PyLong_FromSsize_t(index); }
425+
''',
426+
slots=[
427+
'{Py_mp_length, &my_mp_len}',
428+
'{Py_sq_item, &my_sq_item}',
429+
])
430+
def verify(x):
431+
assert x[5] == 5
432+
assert x.__getitem__(5) == 5
433+
# no sq_length, negative index is just passed to sq_item
434+
assert x[-1] == -1
435+
assert x.__getitem__(-1) == -1
436+
assert x[-20] == -20
437+
assert x.__getitem__(-20) == -20
438+
439+
verify(MyMpLenSqItem())
440+
verify(MyMpLenSqItemHeap())

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@
8282
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.ConvertPIntToPrimitiveNode;
8383
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.GetIndexNode;
8484
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.TransformExceptionFromNativeNode;
85+
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodesFactory.ConvertPIntToPrimitiveNodeGen;
8586
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
8687
import com.oracle.graal.python.builtins.objects.cext.common.CExtToJavaNode;
8788
import com.oracle.graal.python.builtins.objects.cext.common.CExtToNativeNode;
8889
import com.oracle.graal.python.builtins.objects.cext.common.NativeCExtSymbol;
8990
import com.oracle.graal.python.builtins.objects.cext.common.NativePointer;
90-
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodesFactory.ConvertPIntToPrimitiveNodeGen;
9191
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess;
9292
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.StorageToNativeNode;
9393
import com.oracle.graal.python.builtins.objects.floats.PFloat;
@@ -100,6 +100,7 @@
100100
import com.oracle.graal.python.builtins.objects.str.PString;
101101
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
102102
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot;
103+
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotCExtNative;
103104
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotNative;
104105
import com.oracle.graal.python.nodes.ErrorMessages;
105106
import com.oracle.graal.python.nodes.PGuards;
@@ -700,7 +701,7 @@ public static PBuiltinFunction createWrapperFunction(TruffleString name, Object
700701
// ensure that 'callable' is executable via InteropLibrary
701702
Object boundCallable = CExtContext.ensureExecutable(callable, sig);
702703
kwDefaults = ExternalFunctionNodes.createKwDefaults(boundCallable);
703-
slot = new TpSlotNative(boundCallable);
704+
slot = TpSlotNative.createCExtSlot(boundCallable);
704705
}
705706

706707
// generate default values for positional args (if necessary)
@@ -724,6 +725,21 @@ public static PBuiltinFunction createWrapperFunction(TruffleString name, Object
724725
return factory.createWrapperDescriptor(name, type, defaults, kwDefaults, flags, callTarget, slot, sig);
725726
}
726727

728+
/**
729+
* {@link #createWrapperFunction(TruffleString, Object, Object, int, PExternalFunctionWrapper, PythonLanguage, PythonObjectFactory, boolean)}.
730+
*/
731+
@TruffleBoundary
732+
public static PBuiltinFunction createWrapperFunction(TruffleString name, TpSlotCExtNative slot, Object enclosingType, PExternalFunctionWrapper sig, PythonLanguage language,
733+
PythonObjectFactory factory) {
734+
RootCallTarget callTarget = getOrCreateCallTarget(sig, language, name, true, false);
735+
if (callTarget == null) {
736+
return null;
737+
}
738+
var kwDefaults = ExternalFunctionNodes.createKwDefaults(slot.getCallable());
739+
Object[] defaults = PBuiltinFunction.generateDefaults(sig.numDefaults);
740+
return factory.createWrapperDescriptor(name, enclosingType, defaults, kwDefaults, 0, callTarget, slot, sig);
741+
}
742+
727743
private static boolean isClosurePointer(PythonContext context, Object callable, InteropLibrary lib) {
728744
if (lib.isPointer(callable)) {
729745
try {

0 commit comments

Comments
 (0)