Skip to content

Commit d83de55

Browse files
committed
Implement sq_inplace_concat and nb_inplace_add slots
1 parent afcda3c commit d83de55

File tree

20 files changed

+386
-91
lines changed

20 files changed

+386
-91
lines changed

graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ enum SlotKind {
171171
sq_concat("__add__"),
172172
/** seq * number, nb_multiply is tried before */
173173
sq_repeat("__mul__"),
174+
/** seq += seq */
175+
sq_inplace_concat("__iadd__"),
174176
/** mapping length */
175177
mp_length("__len__"),
176178
/** mapping subscript, e.g. o[key], o[i:j] */

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ static String getSlotBaseClass(Slot s) {
5858
"TpSlotBinaryOp.TpSlotBinaryOpBuiltin";
5959
case nb_inplace_add, nb_inplace_subtract, nb_inplace_multiply, nb_inplace_remainder,
6060
nb_inplace_lshift, nb_inplace_rshift, nb_inplace_and, nb_inplace_xor, nb_inplace_or,
61-
nb_inplace_floor_divide, nb_inplace_true_divide, nb_inplace_matrix_multiply ->
61+
nb_inplace_floor_divide, nb_inplace_true_divide, nb_inplace_matrix_multiply,
62+
sq_inplace_concat ->
6263
"TpSlotBinaryOp.TpSlotBinaryIOpBuiltin";
6364
case nb_power -> "TpSlotNbPower.TpSlotNbPowerBuiltin";
6465
case sq_concat -> "TpSlotBinaryFunc.TpSlotSqConcat";
@@ -80,13 +81,15 @@ static String getSlotNodeBaseClass(Slot s) {
8081
case nb_bool -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotInquiry.NbBoolBuiltinNode";
8182
case nb_index, nb_int, nb_float, nb_absolute, nb_positive, nb_negative, nb_invert -> "com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode";
8283
case nb_add, nb_subtract, nb_multiply, nb_remainder, nb_divmod, nb_lshift, nb_rshift, nb_and, nb_xor, nb_or,
83-
nb_floor_divide, nb_true_divide, nb_matrix_multiply,
84-
nb_inplace_add, nb_inplace_subtract, nb_inplace_multiply, nb_inplace_remainder,
85-
nb_inplace_lshift, nb_inplace_rshift, nb_inplace_and, nb_inplace_xor, nb_inplace_or,
86-
nb_inplace_floor_divide, nb_inplace_true_divide, nb_inplace_matrix_multiply ->
84+
nb_floor_divide, nb_true_divide, nb_matrix_multiply ->
8785
"com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryOp.BinaryOpBuiltinNode";
8886
case nb_power -> "com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode";
8987
case sq_concat -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode";
88+
case nb_inplace_add, nb_inplace_subtract, nb_inplace_multiply, nb_inplace_remainder,
89+
nb_inplace_lshift, nb_inplace_rshift, nb_inplace_and, nb_inplace_xor, nb_inplace_or,
90+
nb_inplace_floor_divide, nb_inplace_true_divide, nb_inplace_matrix_multiply,
91+
sq_inplace_concat ->
92+
"com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode";
9093
case sq_length, mp_length -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode";
9194
case sq_item -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode";
9295
case sq_ass_item -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotSqAssItem.SqAssItemBuiltinNode";
@@ -165,6 +168,7 @@ public static String getExtraCtorArgs(TpSlotData slot) {
165168
case nb_inplace_floor_divide -> ", com.oracle.graal.python.nodes.SpecialMethodNames.J___IFLOORDIV__";
166169
case nb_inplace_true_divide -> ", com.oracle.graal.python.nodes.SpecialMethodNames.J___ITRUEDIV__";
167170
case nb_inplace_matrix_multiply -> ", com.oracle.graal.python.nodes.SpecialMethodNames.J___IMATMUL__";
171+
case sq_inplace_concat -> ", com.oracle.graal.python.nodes.SpecialMethodNames.J___IADD__";
168172
default -> "";
169173
};
170174
}

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

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,14 @@ def test_concat_vs_add():
293293
x = SqAdd()
294294

295295
assert x + x is x
296-
# TODO: assert _operator.concat(x, x) is x when _operator.concat is implemented
296+
assert operator.concat(x, x) is x
297297
assert x.__add__(x) is x
298298

299299
class SqAddManaged(SqAdd): pass
300300
x = SqAddManaged()
301301
assert x + x is x
302302
assert x.__add__(x) is x
303-
# TODO: assert _operator.concat(x, x) is x when _operator.concat is implemented
303+
assert operator.concat(x, x) is x
304304

305305
SqAddAndNbAdd = CPyExtHeapType("SqAddAndNbAdd",
306306
slots= [
@@ -314,7 +314,100 @@ class SqAddManaged(SqAdd): pass
314314
x = SqAddAndNbAdd()
315315
y = SqAddAndNbAdd()
316316
assert x + y is y
317-
# TODO: assert _operator.concat(x, x) is x when _operator.concat is implemented
317+
assert operator.concat(x, y) is x
318+
319+
SqAddAndNbAddNoImplemented = CPyExtHeapType("SqAddAndNbAddNoImplemented",
320+
slots= [
321+
'{Py_sq_concat, &concat}',
322+
'{Py_nb_add, &myadd}',
323+
],
324+
code=
325+
'PyObject* concat(PyObject* a, PyObject *b) { Py_INCREF(a); return a; }' +
326+
'PyObject* myadd(PyObject* a, PyObject *b) { Py_RETURN_NOTIMPLEMENTED; }')
327+
x = SqAddAndNbAddNoImplemented()
328+
assert x + 1 is x
329+
330+
331+
def test_sq_inplace_concat_vs_nb_inplace_add():
332+
SqInplaceConcat = CPyExtHeapType(
333+
"SqInplaceConcat",
334+
slots=['{Py_sq_inplace_concat, &inplace_concat}'],
335+
code='PyObject* inplace_concat(PyObject* a, PyObject *b) { return PyUnicode_FromString("inplace_concat"); }',
336+
)
337+
x = SqInplaceConcat()
338+
x += 1
339+
assert x == "inplace_concat"
340+
x = SqInplaceConcat()
341+
assert operator.iconcat(x, []) == "inplace_concat"
342+
343+
SqInplaceConcatAndNbInplaceAdd = CPyExtHeapType(
344+
"SqInplaceConcatAndNbInplaceAdd",
345+
slots=['{Py_sq_inplace_concat, &inplace_concat}', '{Py_nb_inplace_add, &inplace_add}'],
346+
code='''
347+
PyObject* inplace_concat(PyObject* a, PyObject *b) { return PyUnicode_FromString("inplace_concat"); }
348+
PyObject* inplace_add(PyObject* a, PyObject *b) { return PyUnicode_FromString("inplace_add"); }
349+
''',
350+
)
351+
352+
x = SqInplaceConcatAndNbInplaceAdd()
353+
x += 1
354+
assert x == "inplace_add"
355+
x = SqInplaceConcatAndNbInplaceAdd()
356+
assert operator.iconcat(x, 1) == "inplace_concat"
357+
358+
SqInplaceConcatAndNbInplaceAddNotImplemented = CPyExtHeapType(
359+
"InplaceConcatAddNotImpl",
360+
slots=['{Py_sq_inplace_concat, &inplace_concat}', '{Py_nb_inplace_add, &inplace_add}'],
361+
code='''
362+
PyObject* inplace_concat(PyObject* a, PyObject *b) { return PyUnicode_FromString("inplace_concat"); }
363+
PyObject* inplace_add(PyObject* a, PyObject *b) { Py_RETURN_NOTIMPLEMENTED; }
364+
''',
365+
)
366+
367+
x = SqInplaceConcatAndNbInplaceAddNotImplemented()
368+
x += 1
369+
assert x == "inplace_concat"
370+
371+
class InplaceConcatSubclass(SqInplaceConcat):
372+
pass
373+
374+
x = InplaceConcatSubclass()
375+
assert operator.iconcat(x, 1) == "inplace_concat"
376+
377+
SqConcat = CPyExtHeapType(
378+
"SqConcat",
379+
slots=['{Py_sq_concat, &concat}'],
380+
code='PyObject* concat(PyObject* a, PyObject *b) { return PyUnicode_FromString("concat"); }',
381+
)
382+
383+
x = SqConcat()
384+
x += 1
385+
assert x == "concat"
386+
x = SqConcat()
387+
assert operator.iconcat(x, 1) == "concat"
388+
389+
NbInplaceAdd = CPyExtHeapType(
390+
"NbInplaceAdd",
391+
slots=['{Py_nb_inplace_add, &inplace_add}'],
392+
code='PyObject* inplace_add(PyObject* a, PyObject *b) { return PyUnicode_FromString("inplace_add"); }',
393+
)
394+
395+
x = NbInplaceAdd()
396+
assert_raises(TypeError, operator.iconcat, x, 1)
397+
assert_raises(TypeError, operator.iconcat, x, [])
398+
399+
SequenceWithNbInplaceAdd = CPyExtHeapType(
400+
"SequenceWithNbInplaceAdd",
401+
slots=['{Py_nb_inplace_add, &inplace_add}', '{Py_sq_item, &item}'],
402+
code='''
403+
PyObject* inplace_add(PyObject* a, PyObject *b) { return PyUnicode_FromString("inplace_add"); }
404+
PyObject* item(PyObject* a, PyObject *b) { return PyUnicode_FromString("item"); }
405+
''',
406+
)
407+
408+
x = SequenceWithNbInplaceAdd()
409+
assert_raises(TypeError, operator.iconcat, x, 1)
410+
assert operator.iconcat(x, []) == "inplace_add"
318411

319412

320413
def test_incompatible_slots_assignment():

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/OperatorModuleBuiltins.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import com.oracle.graal.python.lib.PyObjectGetItem;
5656
import com.oracle.graal.python.lib.PyObjectIsTrueNode;
5757
import com.oracle.graal.python.lib.PySequenceConcat;
58+
import com.oracle.graal.python.lib.PySequenceInplaceConcat;
5859
import com.oracle.graal.python.nodes.ErrorMessages;
5960
import com.oracle.graal.python.nodes.PRaiseNode;
6061
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -118,6 +119,17 @@ static Object doObject(VirtualFrame frame, Object left, Object right,
118119
}
119120
}
120121

122+
@Builtin(name = "iconcat", minNumOfPositionalArgs = 2)
123+
@GenerateNodeFactory
124+
abstract static class IConcatNode extends PythonBinaryBuiltinNode {
125+
@Specialization
126+
static Object doObject(VirtualFrame frame, Object left, Object right,
127+
@Bind("this") Node inliningTarget,
128+
@Cached PySequenceInplaceConcat concatNode) {
129+
return concatNode.execute(frame, inliningTarget, left, right);
130+
}
131+
}
132+
121133
@Builtin(name = "mul", minNumOfPositionalArgs = 2)
122134
@GenerateNodeFactory
123135
abstract static class MulNode extends PythonBinaryBuiltinNode {

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

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import static com.oracle.graal.python.nodes.SpecialMethodNames.T_KEYS;
6060
import static com.oracle.graal.python.nodes.SpecialMethodNames.T_VALUES;
6161
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___GETITEM__;
62-
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___IADD__;
6362
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___IMUL__;
6463

6564
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
@@ -102,7 +101,6 @@
102101
import com.oracle.graal.python.lib.GetNextNode;
103102
import com.oracle.graal.python.lib.PyIndexCheckNode;
104103
import com.oracle.graal.python.lib.PyIterCheckNode;
105-
import com.oracle.graal.python.lib.PyNumberAddNode;
106104
import com.oracle.graal.python.lib.PyNumberCheckNode;
107105
import com.oracle.graal.python.lib.PyNumberFloatNode;
108106
import com.oracle.graal.python.lib.PyNumberIndexNode;
@@ -118,6 +116,7 @@
118116
import com.oracle.graal.python.lib.PySequenceContainsNode;
119117
import com.oracle.graal.python.lib.PySequenceDelItemNode;
120118
import com.oracle.graal.python.lib.PySequenceGetItemNode;
119+
import com.oracle.graal.python.lib.PySequenceInplaceConcat;
121120
import com.oracle.graal.python.lib.PySequenceIterSearchNode;
122121
import com.oracle.graal.python.lib.PySequenceSetItemNode;
123122
import com.oracle.graal.python.lib.PySequenceSizeNode;
@@ -572,25 +571,11 @@ Object doIt(Object s1, Object s2,
572571
@CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, PyObject}, call = Direct)
573572
abstract static class PySequence_InPlaceConcat extends CApiBinaryBuiltinNode {
574573

575-
@Specialization(guards = {"checkNode.execute(inliningTarget, s1)"}, limit = "1")
574+
@Specialization
576575
static Object concat(Object s1, Object s2,
577576
@Bind("this") Node inliningTarget,
578-
@Cached PyObjectLookupAttr lookupNode,
579-
@Cached CallNode callNode,
580-
@Cached PyNumberAddNode addNode,
581-
@SuppressWarnings("unused") @Exclusive @Cached PySequenceCheckNode checkNode) {
582-
Object iaddCallable = lookupNode.execute(null, inliningTarget, s1, T___IADD__);
583-
if (iaddCallable != PNone.NO_VALUE) {
584-
return callNode.executeWithoutFrame(iaddCallable, s2);
585-
}
586-
return addNode.execute(null, inliningTarget, s1, s2);
587-
}
588-
589-
@Specialization(guards = "!checkNode.execute(inliningTarget, s1)", limit = "1")
590-
static Object concat(Object s1, @SuppressWarnings("unused") Object s2,
591-
@SuppressWarnings("unused") @Exclusive @Cached PySequenceCheckNode checkNode,
592-
@Bind("this") Node inliningTarget) {
593-
throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.OBJ_CANT_BE_CONCATENATED, s1);
577+
@Cached PySequenceInplaceConcat concat) {
578+
return concat.execute(null, inliningTarget, s1, s2);
594579
}
595580
}
596581

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___EQ__;
4545
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GE__;
4646
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GT__;
47-
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___IADD__;
4847
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___IMUL__;
4948
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__;
5049
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__;
@@ -206,7 +205,7 @@ static Object error(@SuppressWarnings("unused") Object left, Object right,
206205
}
207206
}
208207

209-
@Builtin(name = J___IADD__, minNumOfPositionalArgs = 2)
208+
@Slot(value = SlotKind.sq_inplace_concat, isComplex = true)
210209
@GenerateNodeFactory
211210
abstract static class IAddNode extends PythonBinaryBuiltinNode {
212211
@Specialization

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___EQ__;
3434
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GE__;
3535
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GT__;
36-
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___IADD__;
3736
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___IMUL__;
3837
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___INIT__;
3938
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__;
@@ -426,7 +425,7 @@ static Object repr(PByteArray self,
426425
}
427426
}
428427

429-
@Builtin(name = J___IADD__, minNumOfPositionalArgs = 2)
428+
@Slot(value = SlotKind.sq_inplace_concat, isComplex = true)
430429
@GenerateNodeFactory
431430
public abstract static class IAddNode extends PythonBinaryBuiltinNode {
432431
@Specialization

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyAsyncMethods__am_aiter;
4444
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyAsyncMethods__am_anext;
4545
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyAsyncMethods__am_await;
46-
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_inplace_add;
4746
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_inplace_multiply;
4847
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_inplace_power;
4948
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_as_number;
@@ -60,7 +59,6 @@
6059
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___AWAIT__;
6160
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___CALL__;
6261
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___HASH__;
63-
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___IADD__;
6462
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___IMUL__;
6563
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INIT__;
6664
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___IPOW__;
@@ -98,7 +96,6 @@ public enum SlotMethodDef {
9896
// (mq) AM_SEND is an internal function and mostly called from within AWAIT, AITER, ANEXT.
9997
/*- AM_SEND(PyAsyncMethods__am_send, ASYNC_AM_SEND, CallFunctionWrapper::new, MethodsFlags.AM_SEND), */
10098

101-
NB_INPLACE_ADD(PyNumberMethods__nb_inplace_add, T___IADD__, BinaryFuncWrapper::new, MethodsFlags.NB_INPLACE_ADD),
10299
NB_INPLACE_MULTIPLY(PyNumberMethods__nb_inplace_multiply, T___IMUL__, BinaryFuncWrapper::new, MethodsFlags.NB_INPLACE_MULTIPLY),
103100
NB_INPLACE_POWER(PyNumberMethods__nb_inplace_power, T___IPOW__, CallFunctionWrapper::new, MethodsFlags.NB_INPLACE_POWER);
104101

@@ -133,7 +130,6 @@ public enum SlotMethodDef {
133130
static {
134131
initGroup(
135132
PyTypeObject__tp_as_number,
136-
NB_INPLACE_ADD,
137133
NB_INPLACE_MULTIPLY,
138134
NB_INPLACE_POWER);
139135
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ private static Object allocatePyNumberMethods(PythonManagedClass obj, TpSlots sl
151151

152152
writeGroupSlots(CFields.PyTypeObject__tp_as_number, slots, writePointerNode, mem, nullValue);
153153

154-
writePointerNode.write(mem, CFields.PyNumberMethods__nb_inplace_add, getSlot(obj, SlotMethodDef.NB_INPLACE_ADD));
155154
writePointerNode.write(mem, CFields.PyNumberMethods__nb_inplace_multiply, getSlot(obj, SlotMethodDef.NB_INPLACE_MULTIPLY));
156155
writePointerNode.write(mem, CFields.PyNumberMethods__nb_inplace_power, getSlot(obj, SlotMethodDef.NB_INPLACE_POWER));
157156
return mem;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___EQ__;
5858
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GE__;
5959
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GT__;
60-
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___IADD__;
6160
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___IMUL__;
6261
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___INIT__;
6362
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__;
@@ -674,7 +673,7 @@ static int doGeneric(PDeque self) {
674673
}
675674

676675
// deque.__iadd__(v)
677-
@Builtin(name = J___IADD__, minNumOfPositionalArgs = 2)
676+
@Slot(value = SlotKind.sq_inplace_concat, isComplex = true)
678677
@GenerateNodeFactory
679678
public abstract static class DequeInplaceAddNode extends PythonBinaryBuiltinNode {
680679

0 commit comments

Comments
 (0)