diff --git a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java index e3deb6b83c..f6bd3a0d51 100644 --- a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java +++ b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java @@ -97,12 +97,15 @@ enum SlotKind { nb_bool("__bool__"), /** foo + bar */ nb_add("__add__, __radd__"), + nb_multiply("__mul__, __rmul__"), /** sequence length/size */ sq_length("__len__"), /** sequence item: read element at index */ sq_item("__getitem__"), /** seq + seq, nb_add is tried before */ sq_concat("__add__"), + /** seq * number, nb_multiply is tried before */ + sq_repeat("__mul__"), /** mapping length */ mp_length("__len__"), /** mapping subscript, e.g. o[key], o[i:j] */ diff --git a/graalpython/com.oracle.graal.python.cext/src/abstract.c b/graalpython/com.oracle.graal.python.cext/src/abstract.c index e04bd8fca7..018341a899 100644 --- a/graalpython/com.oracle.graal.python.cext/src/abstract.c +++ b/graalpython/com.oracle.graal.python.cext/src/abstract.c @@ -885,6 +885,7 @@ PyNumber_Check(PyObject *o) PyNumberMethods *nb = Py_TYPE(o)->tp_as_number; return nb && (nb->nb_index || nb->nb_int || nb->nb_float || PyComplex_Check(o)); } +#endif // GraalPy /* Binary operators */ @@ -1108,6 +1109,7 @@ ternary_op(PyObject *v, return binary_op(v, w, NB_SLOT(op), op_name); \ } +#if 0 // GraalPy BINARY_FUNC(PyNumber_Or, nb_or, "|") BINARY_FUNC(PyNumber_Xor, nb_xor, "^") BINARY_FUNC(PyNumber_And, nb_and, "&") @@ -1754,6 +1756,7 @@ PySequence_Concat(PyObject *s, PyObject *o) } return type_error("'%.200s' object can't be concatenated", s); } +#endif // GraalPy PyObject * PySequence_Repeat(PyObject *o, Py_ssize_t count) @@ -1786,6 +1789,7 @@ PySequence_Repeat(PyObject *o, Py_ssize_t count) return type_error("'%.200s' object can't be repeated", o); } +#if 0 // GraalPy change PyObject * PySequence_InPlaceConcat(PyObject *s, PyObject *o) { diff --git a/graalpython/com.oracle.graal.python.cext/src/capi.h b/graalpython/com.oracle.graal.python.cext/src/capi.h index d80ee1b81f..c2ef0e289a 100644 --- a/graalpython/com.oracle.graal.python.cext/src/capi.h +++ b/graalpython/com.oracle.graal.python.cext/src/capi.h @@ -194,7 +194,6 @@ Py_LOCAL_SYMBOL int is_builtin_type(PyTypeObject *tp); #define JWRAPPER_METHOD 8 #define JWRAPPER_UNSUPPORTED 9 #define JWRAPPER_ALLOC 10 -#define JWRAPPER_SSIZE_ARG JWRAPPER_ALLOC #define JWRAPPER_GETATTR 11 #define JWRAPPER_SETATTR 12 #define JWRAPPER_RICHCMP 13 @@ -232,6 +231,7 @@ Py_LOCAL_SYMBOL int is_builtin_type(PyTypeObject *tp); #define JWRAPPER_REPR 45 #define JWRAPPER_DESCR_DELETE 46 #define JWRAPPER_DELATTRO 47 +#define JWRAPPER_SSIZE_ARG 48 static inline int get_method_flags_wrapper(int flags) { diff --git a/graalpython/com.oracle.graal.python.cext/src/typeobject.c b/graalpython/com.oracle.graal.python.cext/src/typeobject.c index 41fb61f6a5..53b43b8b72 100644 --- a/graalpython/com.oracle.graal.python.cext/src/typeobject.c +++ b/graalpython/com.oracle.graal.python.cext/src/typeobject.c @@ -9383,6 +9383,7 @@ static int type_ready_graalpy_slot_conv(PyTypeObject* cls) { ADD_SLOT_CONV("__len__", sequences->sq_length, -1, JWRAPPER_LENFUNC); ADD_SLOT_CONV("__add__", sequences->sq_concat, -2, JWRAPPER_BINARYFUNC); ADD_SLOT_CONV("__mul__", sequences->sq_repeat, -2, JWRAPPER_SSIZE_ARG); + ADD_SLOT_CONV("__rmul__", sequences->sq_repeat, -2, JWRAPPER_SSIZE_ARG); ADD_SLOT_CONV("__getitem__", sequences->sq_item, -2, JWRAPPER_GETITEM); ADD_SLOT_CONV("__setitem__", sequences->sq_ass_item, -3, JWRAPPER_SETITEM); ADD_SLOT_CONV("__delitem__", sequences->sq_ass_item, -3, JWRAPPER_DELITEM); diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java index 0ebf99ee08..506bebd187 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java @@ -52,10 +52,10 @@ private static String getSuffix(boolean isComplex) { static String getSlotBaseClass(Slot s) { return switch (s.value()) { case nb_bool -> "TpSlotInquiry.TpSlotInquiryBuiltin"; - case nb_add -> "TpSlotBinaryOp.TpSlotBinaryOpBuiltin"; + case nb_add, nb_multiply -> "TpSlotBinaryOp.TpSlotBinaryOpBuiltin"; case sq_concat -> "TpSlotBinaryFunc.TpSlotSqConcat"; case sq_length, mp_length -> "TpSlotLen.TpSlotLenBuiltin" + getSuffix(s.isComplex()); - case sq_item -> "TpSlotSizeArgFun.TpSlotSizeArgFunBuiltin"; + case sq_item, sq_repeat -> "TpSlotSizeArgFun.TpSlotSizeArgFunBuiltin"; case mp_subscript -> "TpSlotBinaryFunc.TpSlotMpSubscript"; case tp_getattro -> "TpSlotGetAttr.TpSlotGetAttrBuiltin"; case tp_descr_get -> "TpSlotDescrGet.TpSlotDescrGetBuiltin" + getSuffix(s.isComplex()); @@ -68,10 +68,11 @@ static String getSlotNodeBaseClass(Slot s) { return switch (s.value()) { case tp_descr_get -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrGet.DescrGetBuiltinNode"; case nb_bool -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotInquiry.NbBoolBuiltinNode"; - case nb_add -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryOp.BinaryOpBuiltinNode"; + case nb_add, nb_multiply -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryOp.BinaryOpBuiltinNode"; case sq_concat -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode"; case sq_length, mp_length -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode"; case sq_item -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode"; + case sq_repeat -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode"; case mp_subscript -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.MpSubscriptBuiltinNode"; case tp_getattro -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotGetAttr.GetAttrBuiltinNode"; case tp_descr_set -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrSet.DescrSetBuiltinNode"; @@ -84,7 +85,7 @@ static String getUncachedExecuteSignature(SlotKind s) { case nb_bool -> "boolean executeUncached(Object self)"; case tp_descr_get -> "Object executeUncached(Object self, Object obj, Object type)"; case sq_length, mp_length -> "int executeUncached(Object self)"; - case tp_getattro, tp_descr_set, tp_setattro, sq_item, mp_subscript, nb_add, sq_concat -> + case tp_getattro, tp_descr_set, tp_setattro, sq_item, mp_subscript, nb_add, sq_concat, sq_repeat, nb_multiply -> throw new AssertionError("Should not reach here: should be always complex"); }; } @@ -93,7 +94,8 @@ static boolean supportsComplex(SlotKind s) { return switch (s) { case nb_bool -> false; case sq_length, mp_length, tp_getattro, tp_descr_get, tp_descr_set, - tp_setattro, sq_item, mp_subscript, nb_add, sq_concat -> + tp_setattro, sq_item, mp_subscript, nb_add, sq_concat, + sq_repeat, nb_multiply -> true; }; } @@ -101,7 +103,9 @@ static boolean supportsComplex(SlotKind s) { static boolean supportsSimple(SlotKind s) { return switch (s) { case nb_bool, sq_length, mp_length, tp_descr_get -> true; - case tp_getattro, tp_descr_set, tp_setattro, sq_item, mp_subscript, nb_add, sq_concat -> false; + case tp_getattro, tp_descr_set, tp_setattro, sq_item, mp_subscript, + nb_add, sq_concat, sq_repeat, nb_multiply -> + false; }; } @@ -110,7 +114,8 @@ static String getUncachedExecuteCall(SlotKind s) { case nb_bool -> "executeBool(null, self)"; case sq_length, mp_length -> "executeInt(null, self)"; case tp_descr_get -> "execute(null, self, obj, type)"; - case tp_getattro, tp_descr_set, tp_setattro, sq_item, mp_subscript, nb_add, sq_concat -> + case tp_getattro, tp_descr_set, tp_setattro, sq_item, mp_subscript, + nb_add, sq_concat, nb_multiply, sq_repeat -> throw new AssertionError("Should not reach here: should be always complex"); }; } @@ -118,10 +123,8 @@ static String getUncachedExecuteCall(SlotKind s) { public static String getExtraCtorArgs(TpSlotData slot) { return switch (slot.slot().value()) { case nb_add -> ", com.oracle.graal.python.nodes.SpecialMethodNames.J___ADD__"; - case nb_bool, tp_setattro, tp_getattro, - tp_descr_set, tp_descr_get, mp_subscript, - mp_length, sq_concat, sq_item, sq_length -> - ""; + case nb_multiply -> ", com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__"; + default -> ""; }; } } diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/fuzzer_test10.c b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/fuzzer_test10.c new file mode 100644 index 0000000000..57b58255b6 --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/fuzzer_test10.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +// Generated by the slots_fuzzer.py +#include + +PyObject *global_stash1; +PyObject *global_stash2; + +int Native0_nb_bool(PyObject *self) { return 1; } +PyObject *Native0_nb_add(PyObject *self, PyObject *other) { + return Py_NewRef(self); +} +Py_ssize_t Native0_sq_length(PyObject *self) { return 1; } +PyObject *Native0_sq_concat(PyObject *self, PyObject *other) { + return PyLong_FromLong(10); +} +PyObject *Native0_sq_repeat(PyObject *self, Py_ssize_t count) { + return PyLong_FromLong(count); +} +Py_ssize_t Native0_mp_length(PyObject *self) { return 42; } +PyObject *Native0_tp_getattr(PyObject *self, char *name) { + return Py_NewRef(self); +} +PyObject *Native0_tp_getattro(PyObject *self, PyObject *name) { + return Py_NewRef(self); +} +PyObject *Native0_tp_descr_get(PyObject *self, PyObject *key, PyObject *type) { + Py_RETURN_NONE; +} +int Native0_tp_descr_set(PyObject *self, PyObject *key, PyObject *value) { + return 0; +} + +PyNumberMethods Native0_tp_as_number = { + .nb_bool = &Native0_nb_bool, + .nb_add = &Native0_nb_add, +}; +PySequenceMethods Native0_tp_as_sequence = { + .sq_length = &Native0_sq_length, + .sq_concat = &Native0_sq_concat, + .sq_repeat = &Native0_sq_repeat, +}; +PyMappingMethods Native0_tp_as_mapping = { + .mp_length = &Native0_mp_length, +}; + +static PyTypeObject CustomType_Native0 = { + .ob_base = PyVarObject_HEAD_INIT(NULL, 0).tp_name = "test10.Native0", + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_as_number = &Native0_tp_as_number, + .tp_as_sequence = &Native0_tp_as_sequence, + .tp_as_mapping = &Native0_tp_as_mapping, + .tp_getattr = &Native0_tp_getattr, + .tp_getattro = &Native0_tp_getattro, + .tp_descr_get = &Native0_tp_descr_get, + .tp_descr_set = &Native0_tp_descr_set, + +}; + +static PyObject *create_Native0(PyObject *module, PyObject *args) { + if (PyType_Ready(&CustomType_Native0) < 0) + return NULL; + Py_INCREF(&CustomType_Native0); + return (PyObject *)&CustomType_Native0; +} + +static struct PyMethodDef test_module_methods[] = { + {"create_Native0", (PyCFunction)create_Native0, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL}}; +static PyModuleDef test_module = {PyModuleDef_HEAD_INIT, + "fuzzer_test10", + "", + -1, + test_module_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC PyInit_fuzzer_test10(void) { + return PyModule_Create(&test_module); +} diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py index 05260c3b88..fe855632b4 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py @@ -46,6 +46,8 @@ __dir__ = __file__.rpartition("/")[0] +from .test_modsupport import MySeq + def _safe_check(v, type_check): try: @@ -291,6 +293,27 @@ def __len__(self): return 42 +class SeqWithMulAdd: + def __getitem__(self, item): + return item + + def __mul__(self, other): + return "mul:" + str(other) + + def __add__(self, other): + return "add:" + str(other) + + def __str__(self): + return "SeqWithMulAdd" + +class NonSeqWithMulAdd: + def __mul__(self, other): + return "not expected!" + + def __add__(self, other): + return "not expected!" + + class DictSubclassWithSequenceMethods(dict): def __getitem__(self, key): return key @@ -298,6 +321,12 @@ def __getitem__(self, key): def __setitem__(self, key, value): pass + def __add__(self, other): + return "not expected!" + + def __mul__(self, other): + return "not expected!" + def _default_bin_arith_args(): return ( @@ -1487,8 +1516,17 @@ def _reference_delslice(args): cmpfunc=unhandled_error_compare ) + def _reference_seq_repeat(args): + match args[0]: + case SeqWithMulAdd(): + return "mul:" + str(args[1]) + case NonSeqWithMulAdd() | DictSubclassWithSequenceMethods(): + raise TypeError(f"{type(args[1])} object can't be repeated") + case _: + return args[0] * args[1] + test_PySequence_Repeat = CPyExtFunction( - lambda args: args[0] * args[1], + _reference_seq_repeat, lambda: ( ((1,), 0), ((1,), 1), @@ -1500,6 +1538,9 @@ def _reference_delslice(args): ("hello", 1), ("hello", 3), ({}, 0), + (SeqWithMulAdd(), 42), + (NonSeqWithMulAdd(), 24), + (DictSubclassWithSequenceMethods(), 5), ), resultspec="O", argspec='On', @@ -1527,8 +1568,19 @@ def _reference_delslice(args): cmpfunc=unhandled_error_compare ) + def _reference_seq_concat(args): + match args[0]: + case SeqWithMulAdd(): + if hasattr(args[1], "__getitem__"): + return "add:" + str(args[1]) + raise TypeError("SeqWithMulAdd object can't be concatenated") + case NonSeqWithMulAdd() | DictSubclassWithSequenceMethods(): + raise TypeError(f"{type(args[1])} object can't be concatenated") + case _: + return args[0] + args[1] + test_PySequence_Concat = CPyExtFunction( - lambda args: args[0] + args[1], + _reference_seq_concat, lambda: ( ((1,), tuple()), ((1,), list()), @@ -1542,6 +1594,13 @@ def _reference_delslice(args): ("hello", ""), ({}, []), ([], {}), + (SeqWithMulAdd(), 1), + (SeqWithMulAdd(), SeqWithMulAdd()), + (SeqWithMulAdd(), [1,2,3]), + (NonSeqWithMulAdd(), 2), + (NonSeqWithMulAdd(), [1,2,3]), + (DictSubclassWithSequenceMethods(), (1,2,3)), + ((1,2,3), DictSubclassWithSequenceMethods()), ), resultspec="O", argspec='OO', diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py index bac14c089e..932c54b5f9 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py @@ -37,7 +37,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import sys -from . import CPyExtType, CPyExtHeapType, compile_module_from_string, assert_raises +from . import CPyExtType, CPyExtHeapType, compile_module_from_string, assert_raises, compile_module_from_file SlotsGetter = CPyExtType("SlotsGetter", """ @@ -583,4 +583,19 @@ def test_nb_add_sq_concat_static_managed_heap_inheritance(): class ManagedDummy(NbAddSqConcatStaticType): pass - assert SlotsGetter.get_nb_add(ManagedDummy()) == SlotsGetter.get_nb_add(NbAddSqConcatStaticType()) \ No newline at end of file + assert SlotsGetter.get_nb_add(ManagedDummy()) == SlotsGetter.get_nb_add(NbAddSqConcatStaticType()) + +def test_sq_repeat_mul_without_rmul_inheritance(): + mod = compile_module_from_file("fuzzer_test10") + Native0 = mod.create_Native0((object, )) + class Managed1(Native0): + def __add__(self): return self + def __mul__(self,o): return "__mul__result: " + str(o) + def __radd__(self): return NotImplemented + def __len__(self): return 1 + def __getattribute__(self,name): return name + def __get__(self,obj,objtype=None): return "dummy" + def __setattr__(self,name,value): return None + + assert 3 * Managed1() == 3 + assert Managed1() * 3 == "__mul__result: 3" \ No newline at end of file diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_array.py b/graalpython/com.oracle.graal.python.test/src/tests/test_array.py index 3f2a15a1b8..f0cb704814 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_array.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_array.py @@ -111,3 +111,12 @@ def test_array_native_storage(): del a[2:] a.insert(1, -1) assert a == array('l', [1, -1, 3]) + +def test_mul(): + a = array('l', [1, 2, 3]) + assert len(a * 0) == 0 + + b = a * 1 + a[2] = 42 + assert list(a) == [1, 2, 42] + assert list(b) == [1, 2, 3] \ No newline at end of file diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index ecb73dfccb..1b82934ae4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -114,6 +114,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Slot; import com.oracle.graal.python.builtins.modules.WeakRefModuleBuiltins; +import com.oracle.graal.python.builtins.modules.ctypes.CDataTypeSequenceBuiltins; import com.oracle.graal.python.builtins.modules.ctypes.CFieldBuiltins; import com.oracle.graal.python.builtins.modules.ctypes.PyCArrayBuiltins; import com.oracle.graal.python.builtins.modules.ctypes.PyCFuncPtrBuiltins; @@ -410,12 +411,17 @@ public enum PythonBuiltinClassType implements TruffleObject { CArgObject("CArgObject", Flags.PUBLIC_BASE_WODICT), CThunkObject("CThunkObject", J__CTYPES, Flags.PUBLIC_BASE_WODICT), StgDict("StgDict", Flags.PRIVATE_DERIVED_WODICT, DICT_M_FLAGS, StgDictBuiltins.SLOTS), - PyCStructType("PyCStructType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCSTRUCTTYPE_M_FLAGS, PyCStructTypeBuiltins.SLOTS), - UnionType("UnionType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, UNIONTYPE_M_FLAGS, com.oracle.graal.python.builtins.modules.ctypes.UnionTypeBuiltins.SLOTS), - PyCPointerType("PyCPointerType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCPOINTERTYPE_M_FLAGS), - PyCArrayType("PyCArrayType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCARRAYTYPE_M_FLAGS), - PyCSimpleType("PyCSimpleType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCSIMPLETYPE_M_FLAGS), - PyCFuncPtrType("PyCFuncPtrType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCFUNCPTRTYPE_M_FLAGS), + PyCStructType("PyCStructType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCSTRUCTTYPE_M_FLAGS, TpSlots.merge(CDataTypeSequenceBuiltins.SLOTS, PyCStructTypeBuiltins.SLOTS)), + UnionType( + "UnionType", + J__CTYPES, + Flags.PUBLIC_BASE_WODICT, + UNIONTYPE_M_FLAGS, + TpSlots.merge(CDataTypeSequenceBuiltins.SLOTS, com.oracle.graal.python.builtins.modules.ctypes.UnionTypeBuiltins.SLOTS)), + PyCPointerType("PyCPointerType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCPOINTERTYPE_M_FLAGS, CDataTypeSequenceBuiltins.SLOTS), + PyCArrayType("PyCArrayType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCARRAYTYPE_M_FLAGS, CDataTypeSequenceBuiltins.SLOTS), + PyCSimpleType("PyCSimpleType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCSIMPLETYPE_M_FLAGS, CDataTypeSequenceBuiltins.SLOTS), + PyCFuncPtrType("PyCFuncPtrType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCFUNCPTRTYPE_M_FLAGS, CDataTypeSequenceBuiltins.SLOTS), Structure("Structure", J__CTYPES, Flags.PUBLIC_BASE_WODICT), /*- type = PyCStructType */ Union("Union", J__CTYPES, Flags.PUBLIC_BASE_WODICT), /*- type = UnionType */ PyCPointer("_Pointer", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCPOINTER_M_FLAGS, PyCPointerBuiltins.SLOTS), /*- type = PyCPointerType */ diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/OperatorModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/OperatorModuleBuiltins.java index a5e07cc155..683953d681 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/OperatorModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/OperatorModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -51,8 +51,10 @@ import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary; import com.oracle.graal.python.lib.PyNumberIndexNode; +import com.oracle.graal.python.lib.PyNumberMultiplyNode; import com.oracle.graal.python.lib.PyObjectGetItem; import com.oracle.graal.python.lib.PyObjectIsTrueNode; +import com.oracle.graal.python.lib.PySequenceConcat; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; @@ -106,6 +108,28 @@ static Object doObject(VirtualFrame frame, Object value, Object index, } } + @Builtin(name = "concat", minNumOfPositionalArgs = 2) + @GenerateNodeFactory + abstract static class ConcatNode extends PythonBinaryBuiltinNode { + @Specialization + static Object doObject(VirtualFrame frame, Object left, Object right, + @Bind("this") Node inliningTarget, + @Cached PySequenceConcat concatNode) { + return concatNode.execute(frame, inliningTarget, left, right); + } + } + + @Builtin(name = "mul", minNumOfPositionalArgs = 2) + @GenerateNodeFactory + abstract static class MulNode extends PythonBinaryBuiltinNode { + @Specialization + static Object doObject(VirtualFrame frame, Object left, Object right, + @Bind("this") Node inliningTarget, + @Cached PyNumberMultiplyNode mulNode) { + return mulNode.execute(frame, inliningTarget, left, right); + } + } + // _compare_digest @Builtin(name = "_compare_digest", minNumOfPositionalArgs = 2) @TypeSystemReference(PythonArithmeticTypes.class) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java index c8b5c44189..1a776fbc27 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextAbstractBuiltins.java @@ -104,6 +104,7 @@ import com.oracle.graal.python.lib.PyNumberCheckNode; import com.oracle.graal.python.lib.PyNumberFloatNode; import com.oracle.graal.python.lib.PyNumberIndexNode; +import com.oracle.graal.python.lib.PyNumberMultiplyNode; import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectGetItem; @@ -125,7 +126,6 @@ import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode; import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode; import com.oracle.graal.python.nodes.expression.BinaryArithmetic; -import com.oracle.graal.python.nodes.expression.BinaryArithmetic.MulNode; import com.oracle.graal.python.nodes.expression.BinaryOpNode; import com.oracle.graal.python.nodes.expression.InplaceArithmetic; import com.oracle.graal.python.nodes.expression.LookupAndCallInplaceNode; @@ -547,30 +547,6 @@ static int contains(Object haystack, Object needle, } } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, Py_ssize_t}, call = Direct) - abstract static class PySequence_Repeat extends CApiBinaryBuiltinNode { - @Specialization(guards = "checkNode.execute(inliningTarget, obj)") - Object repeat(Object obj, long n, - @SuppressWarnings("unused") @Bind("this") Node inliningTarget, - @SuppressWarnings("unused") @Shared("check") @Cached PySequenceCheckNode checkNode, - @Cached("createMul()") MulNode mulNode) { - return mulNode.executeObject(null, obj, n); - } - - @Specialization(guards = "!checkNode.execute(inliningTarget, obj)") - static Object repeat(Object obj, @SuppressWarnings("unused") Object n, - @SuppressWarnings("unused") @Bind("this") Node inliningTarget, - @SuppressWarnings("unused") @Shared("check") @Cached PySequenceCheckNode checkNode, - @Cached PRaiseNode raiseNode) { - throw raiseNode.raise(TypeError, ErrorMessages.OBJ_CANT_BE_REPEATED, obj); - } - - @NeverDefault - protected MulNode createMul() { - return (MulNode) BinaryArithmetic.Mul.create(); - } - } - @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, Py_ssize_t}, call = Direct) abstract static class PySequence_InPlaceRepeat extends CApiBinaryBuiltinNode { @Specialization(guards = {"checkNode.execute(inliningTarget, obj)"}, limit = "1") @@ -578,14 +554,14 @@ static Object repeat(Object obj, long n, @Bind("this") Node inliningTarget, @Cached PyObjectLookupAttr lookupNode, @Cached CallNode callNode, - @Cached("createMul()") MulNode mulNode, + @Cached("createMul()") PyNumberMultiplyNode mulNode, @SuppressWarnings("unused") @Exclusive @Cached PySequenceCheckNode checkNode) { Object imulCallable = lookupNode.execute(null, inliningTarget, obj, T___IMUL__); if (imulCallable != PNone.NO_VALUE) { Object ret = callNode.executeWithoutFrame(imulCallable, n); return ret; } - return mulNode.executeObject(null, obj, n); + return mulNode.execute(null, inliningTarget, obj, n); } @Specialization(guards = "!checkNode.execute(inliningTarget, obj)", limit = "1") @@ -595,10 +571,6 @@ static Object repeat(Object obj, @SuppressWarnings("unused") Object n, @Cached PRaiseNode raiseNode) { throw raiseNode.raise(TypeError, ErrorMessages.OBJ_CANT_BE_REPEATED, obj); } - - protected MulNode createMul() { - return (MulNode) BinaryArithmetic.Mul.create(); - } } @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, PyObject}, call = Direct) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/CDataTypeSequenceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/CDataTypeSequenceBuiltins.java index 86938e81b5..b5524c2374 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/CDataTypeSequenceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/CDataTypeSequenceBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -51,15 +51,14 @@ import static com.oracle.graal.python.builtins.modules.ctypes.PyCPointerTypeBuiltins.T__TYPE_; import static com.oracle.graal.python.nodes.ErrorMessages.ARRAY_LENGTH_MUST_BE_0_NOT_D; import static com.oracle.graal.python.nodes.ErrorMessages.EXPECTED_A_TYPE_OBJECT; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; import java.util.List; import com.oracle.graal.python.PythonLanguage; -import com.oracle.graal.python.annotations.ArgumentClinic; -import com.oracle.graal.python.builtins.Builtin; +import com.oracle.graal.python.annotations.Slot; +import com.oracle.graal.python.annotations.Slot.SlotKind; import com.oracle.graal.python.builtins.CoreFunctions; import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.modules.ctypes.CtypesModuleBuiltins.CtypesThreadState; @@ -70,14 +69,13 @@ import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode; import com.oracle.graal.python.builtins.objects.tuple.PTuple; +import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; -import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode; -import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; -import com.oracle.graal.python.nodes.function.builtins.clinic.IndexConversionNode; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PythonObjectFactory; import com.oracle.truffle.api.dsl.Bind; @@ -98,22 +96,16 @@ PyCSimpleType, }) public final class CDataTypeSequenceBuiltins extends PythonBuiltins { + public static final TpSlots SLOTS = CDataTypeSequenceBuiltinsSlotsGen.SLOTS; @Override protected List> getNodeFactories() { return CDataTypeSequenceBuiltinsFactory.getFactories(); } - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2, parameterNames = {"itemtype", "length"}) - @ArgumentClinic(name = "length", conversionClass = IndexConversionNode.class) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory - abstract static class RepeatNode extends PythonBinaryClinicBuiltinNode { - - @Override - protected ArgumentClinicProvider getArgumentClinic() { - return CDataTypeSequenceBuiltinsClinicProviders.RepeatNodeClinicProviderGen.INSTANCE; - } - + abstract static class RepeatNode extends SqRepeatBuiltinNode { // TODO: weakref ctypes.cache values @Specialization(guards = "length >= 0") static Object PyCArrayType_from_ctype(VirtualFrame frame, Object itemtype, int length, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java index 68deb9ea94..439512208c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java @@ -50,11 +50,9 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___SETITEM__; import static com.oracle.graal.python.nodes.StringLiterals.T_COMMA_SPACE; import static com.oracle.graal.python.nodes.StringLiterals.T_LBRACKET; @@ -94,6 +92,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.lib.GetNextNode; import com.oracle.graal.python.lib.PyIndexCheckNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; @@ -155,8 +154,10 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedByteValueProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilder; import com.oracle.truffle.api.strings.TruffleStringIterator; @@ -223,38 +224,42 @@ static Object error(@SuppressWarnings("unused") Object left, Object right, } } - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"$self", "value"}) - @ArgumentClinic(name = "value", conversion = ArgumentClinic.ClinicConversion.Index) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory - abstract static class MulNode extends PythonBinaryClinicBuiltinNode { - @Specialization - Object concat(PArray self, int value, + abstract static class MulNode extends SqRepeatBuiltinNode { + @Specialization(guards = "self.getLength() > 0") + static PArray concat(PArray self, int valueIn, + @Bind("this") Node inliningTarget, @CachedLibrary(limit = "2") PythonBufferAccessLibrary bufferLib, + @Cached InlinedBranchProfile negativeSize, + @Cached InlinedLoopConditionProfile loopProfile, @Cached PythonObjectFactory factory) { + int value = valueIn; + if (value < 0) { + negativeSize.enter(inliningTarget); + value = 0; + } try { int newLength = Math.max(PythonUtils.multiplyExact(self.getLength(), value), 0); PArray newArray = factory.createArray(self.getFormatString(), self.getFormat(), newLength); int segmentLength = self.getBytesLength(); - for (int i = 0; i < value; i++) { + loopProfile.profileCounted(inliningTarget, value); + for (int i = 0; loopProfile.inject(inliningTarget, i < value); i++) { bufferLib.readIntoBuffer(self.getBuffer(), 0, newArray.getBuffer(), segmentLength * i, segmentLength, bufferLib); } return newArray; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw PRaiseNode.raiseUncached(this, MemoryError); + throw PRaiseNode.raiseUncached(inliningTarget, MemoryError); } } - @Override - protected ArgumentClinicProvider getArgumentClinic() { - return ArrayBuiltinsClinicProviders.MulNodeClinicProviderGen.INSTANCE; + @Fallback + static PArray doZeroSize(Object self, @SuppressWarnings("unused") int value) { + return (PArray) self; } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"$self", "value"}) - abstract static class RMulNode extends MulNode { - } - @Builtin(name = J___IMUL__, minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"$self", "value"}) @ArgumentClinic(name = "value", conversion = ArgumentClinic.ClinicConversion.Index) @GenerateNodeFactory diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java index 98fe6e3ec0..c229021a71 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java @@ -48,9 +48,7 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___HASH__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.StringLiterals.T_EMPTY_STRING; import static com.oracle.graal.python.nodes.StringLiterals.T_IGNORE; import static com.oracle.graal.python.nodes.StringLiterals.T_REPLACE; @@ -107,6 +105,7 @@ import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.PyNumberIndexNode; import com.oracle.graal.python.nodes.ErrorMessages; @@ -328,19 +327,17 @@ static PBytesLike add(VirtualFrame frame, Object self, Object other, } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory - public abstract static class MulNode extends PythonBinaryBuiltinNode { + public abstract static class MulNode extends SqRepeatBuiltinNode { @Specialization - static PBytesLike mul(VirtualFrame frame, Object self, Object times, + static PBytesLike mul(VirtualFrame frame, Object self, int times, @Bind("this") Node inliningTarget, @Cached GetBytesStorage getBytesStorage, - @Cached PyNumberAsSizeNode asSizeNode, @Cached("createWithOverflowError()") SequenceStorageNodes.RepeatNode repeatNode, @Cached BytesNodes.CreateBytesNode create, @Cached PythonObjectFactory factory) { - SequenceStorage res = repeatNode.execute(frame, getBytesStorage.execute(inliningTarget, self), asSizeNode.executeExact(frame, inliningTarget, times)); + SequenceStorage res = repeatNode.execute(frame, getBytesStorage.execute(inliningTarget, self), times); return create.execute(inliningTarget, factory, self, res); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java index 547d8eb5ed..c73b30f9b9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java @@ -426,6 +426,7 @@ public final class CApiFunction { @CApiBuiltin(name = "PySequence_Length", ret = Py_ssize_t, args = {PyObject}, call = CImpl) @CApiBuiltin(name = "PySequence_SetItem", ret = Int, args = {PyObject, Py_ssize_t, PyObject}, call = CImpl) @CApiBuiltin(name = "PySequence_Size", ret = Py_ssize_t, args = {PyObject}, call = CImpl) + @CApiBuiltin(name = "PySequence_Repeat", ret = PyObject, args = {PyObject, Py_ssize_t}, call = CImpl) @CApiBuiltin(name = "PySlice_AdjustIndices", ret = Py_ssize_t, args = {Py_ssize_t, PY_SSIZE_T_PTR, PY_SSIZE_T_PTR, Py_ssize_t}, call = CImpl) @CApiBuiltin(name = "PySlice_Start", ret = PyObject, args = {PySliceObject}, call = CImpl) @CApiBuiltin(name = "PySlice_Step", ret = PyObject, args = {PySliceObject}, call = CImpl) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 18d2331c48..41693838d1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -353,12 +353,9 @@ public enum PExternalFunctionWrapper implements NativeCExtSymbol { VARARGS(5, PyObjectTransfer, PyObject, PyObject), // METH_VARARGS NOARGS(6, PyObjectTransfer, PyObject, PyObject), // METH_NOARGS O(7, PyObjectTransfer, PyObject, PyObject), // METH_O - METHOD(8, PyObjectTransfer, PyObject, PyTypeObject, Pointer, Py_ssize_t, PyObject), // METH_FASTCALL - // | - // METH_KEYWORDS - // | - // METH_METHOD - ALLOC(10, PyObjectTransfer, PyObject, Py_ssize_t), + // METH_FASTCALL | METH_KEYWORDS | METH_METHOD: + METHOD(8, PyObjectTransfer, PyObject, PyTypeObject, Pointer, Py_ssize_t, PyObject), + ALLOC(10, PyObjectTransfer, PyTypeObject, Py_ssize_t), GETATTR(11, PyObjectTransfer, PyObject, CharPtrAsTruffleString), SETATTR(12, InitResult, PyObject, CharPtrAsTruffleString, PyObject), RICHCMP(13, PyObjectTransfer, PyObject, PyObject, Int), @@ -395,7 +392,8 @@ public enum PExternalFunctionWrapper implements NativeCExtSymbol { TP_STR(44, PyObjectTransfer, PyObject), TP_REPR(45, PyObjectTransfer, PyObject), DESCR_DELETE(46, InitResult, PyObject, PyObject, PyObject), // the last one is always NULL - DELATTRO(47, InitResult, PyObject, PyObject, PyObject); // the last one is always NULL + DELATTRO(47, InitResult, PyObject, PyObject, PyObject), // the last one is always NULL + SSIZE_ARG(48, PyObjectTransfer, PyObject, Py_ssize_t); private static int defaults(int x) { return x; @@ -466,6 +464,7 @@ static RootCallTarget getOrCreateCallTarget(PExternalFunctionWrapper sig, Python Function rootNodeFunction; switch (sig) { case ALLOC: + case SSIZE_ARG: nodeKlass = AllocFuncRootNode.class; rootNodeFunction = doArgAndResultConversion ? l -> new AllocFuncRootNode(l, name, sig) : l -> new AllocFuncRootNode(l, name); break; @@ -1661,6 +1660,7 @@ public Signature getSignature() { /** * Implements semantics of {@code typeobject.c: wrap_sq_item}. */ + // TODO: can we remove this??? static final class GetItemRootNode extends MethodDescriptorRoot { private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyProcsWrapper.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyProcsWrapper.java index 44afecd836..c324355482 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyProcsWrapper.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyProcsWrapper.java @@ -308,6 +308,10 @@ public static BinaryOpSlotFuncWrapper createAdd(TpSlotManaged delegate) { return new BinaryOpSlotFuncWrapper(delegate, BinaryOpSlot.NB_ADD); } + public static BinaryOpSlotFuncWrapper createMultiply(TpSlotManaged delegate) { + return new BinaryOpSlotFuncWrapper(delegate, BinaryOpSlot.NB_MULTIPLY); + } + @ExportMessage Object execute(Object[] arguments, @Bind("$node") Node inliningTarget, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/SlotMethodDef.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/SlotMethodDef.java index 9c495b8482..f766af621e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/SlotMethodDef.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/SlotMethodDef.java @@ -64,7 +64,6 @@ import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_int; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_invert; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_lshift; -import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_multiply; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_negative; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_or; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_positive; @@ -75,10 +74,8 @@ import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_true_divide; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyNumberMethods__nb_xor; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PySequenceMethods__sq_ass_item; -import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PySequenceMethods__sq_repeat; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_as_mapping; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_as_number; -import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_as_sequence; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_call; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_hash; import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_init; @@ -116,7 +113,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___IXOR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___LSHIFT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEG__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEXT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___OR__; @@ -137,7 +133,6 @@ import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.InitWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.ObjobjargWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.RichcmpFunctionWrapper; -import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.SsizeargfuncWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.SsizeobjargfuncWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.TernaryFunctionWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.PyProcsWrapper.UnaryFuncWrapper; @@ -167,7 +162,6 @@ public enum SlotMethodDef { /*- AM_SEND(PyAsyncMethods__am_send, ASYNC_AM_SEND, TernaryFunctionWrapper::new, MethodsFlags.AM_SEND), */ SQ_ASS_ITEM(PySequenceMethods__sq_ass_item, T___SETITEM__, SsizeobjargfuncWrapper::new, MethodsFlags.SQ_ASS_ITEM), - SQ_REPEAT(PySequenceMethods__sq_repeat, T___MUL__, SsizeargfuncWrapper::new, MethodsFlags.SQ_REPEAT), NB_ABSOLUTE(PyNumberMethods__nb_absolute, T___ABS__, UnaryFuncWrapper::new, MethodsFlags.NB_ABSOLUTE), NB_DIVMOD(PyNumberMethods__nb_divmod, T___DIVMOD__, BinaryFuncWrapper::new, MethodsFlags.NB_DIVMOD), @@ -189,7 +183,6 @@ public enum SlotMethodDef { NB_INT(PyNumberMethods__nb_int, T___INT__, UnaryFuncWrapper::new, MethodsFlags.NB_INT), NB_INVERT(PyNumberMethods__nb_invert, T___INVERT__, UnaryFuncWrapper::new, MethodsFlags.NB_INVERT), NB_LSHIFT(PyNumberMethods__nb_lshift, T___LSHIFT__, BinaryFuncWrapper::new, MethodsFlags.NB_LSHIFT), - NB_MULTIPLY(PyNumberMethods__nb_multiply, T___MUL__, BinaryFuncWrapper::new, MethodsFlags.NB_MULTIPLY), NB_NEGATIVE(PyNumberMethods__nb_negative, T___NEG__, UnaryFuncWrapper::new, MethodsFlags.NB_NEGATIVE), NB_OR(PyNumberMethods__nb_or, T___OR__, BinaryFuncWrapper::new, MethodsFlags.NB_OR), NB_POSITIVE(PyNumberMethods__nb_positive, T___POS__, UnaryFuncWrapper::new, MethodsFlags.NB_POSITIVE), @@ -236,10 +229,6 @@ public enum SlotMethodDef { // // Similarly for NB_ADD/NB_MUL (wrap_binaryfunc_l) and // SQ_CONCAT/SQ_REPEAT (wrap_binaryfunc) - - initGroup( - PyTypeObject__tp_as_sequence, - SQ_REPEAT); initGroup( PyTypeObject__tp_as_mapping, MP_ASS_SUBSCRIPT); @@ -265,7 +254,6 @@ public enum SlotMethodDef { NB_INT, NB_INVERT, NB_LSHIFT, - NB_MULTIPLY, NB_NEGATIVE, NB_OR, NB_POSITIVE, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ToNativeTypeNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ToNativeTypeNode.java index a99cb95f11..7fb486719d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ToNativeTypeNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ToNativeTypeNode.java @@ -176,7 +176,6 @@ private static Object allocatePyNumberMethods(PythonManagedClass obj, TpSlots sl writePointerNode.write(mem, CFields.PyNumberMethods__nb_invert, getSlot(obj, SlotMethodDef.NB_INVERT)); writePointerNode.write(mem, CFields.PyNumberMethods__nb_lshift, getSlot(obj, SlotMethodDef.NB_LSHIFT)); writePointerNode.write(mem, CFields.PyNumberMethods__nb_matrix_multiply, nullValue); - writePointerNode.write(mem, CFields.PyNumberMethods__nb_multiply, getSlot(obj, SlotMethodDef.NB_MULTIPLY)); writePointerNode.write(mem, CFields.PyNumberMethods__nb_negative, getSlot(obj, SlotMethodDef.NB_NEGATIVE)); writePointerNode.write(mem, CFields.PyNumberMethods__nb_or, getSlot(obj, SlotMethodDef.NB_OR)); writePointerNode.write(mem, CFields.PyNumberMethods__nb_positive, getSlot(obj, SlotMethodDef.NB_POSITIVE)); @@ -198,7 +197,6 @@ private static Object allocatePySequenceMethods(PythonManagedClass obj, TpSlots // TODO: Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL in CPython, so // this may have unintended effects - writePointerNode.write(mem, CFields.PySequenceMethods__sq_repeat, getSlot(obj, SlotMethodDef.SQ_REPEAT)); writePointerNode.write(mem, CFields.PySequenceMethods__was_sq_slice, nullValue); writePointerNode.write(mem, CFields.PySequenceMethods__sq_ass_item, getSlot(obj, SlotMethodDef.SQ_ASS_ITEM)); writePointerNode.write(mem, CFields.PySequenceMethods__was_sq_ass_slice, nullValue); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDef.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDef.java index 9adf67769c..81803d6aff 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDef.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDef.java @@ -386,7 +386,7 @@ enum HPySlot { HPY_SQ_INPLACE_REPEAT(43, NO_TP_SLOT, HPySlotWrapper.INDEXARGFUNC, T___IMUL__), HPY_SQ_ITEM(44, TpSlotMeta.SQ_ITEM, HPySlotWrapper.SQ_ITEM, T___GETITEM__), HPY_SQ_LENGTH(45, TpSlotMeta.SQ_LENGTH, HPySlotWrapper.LENFUNC, T___LEN__), - HPY_SQ_REPEAT(46, NO_TP_SLOT, HPySlotWrapper.INDEXARGFUNC, T___MUL__, T___RMUL__), + HPY_SQ_REPEAT(46, TpSlotMeta.SQ_REPEAT, HPySlotWrapper.INDEXARGFUNC, T___MUL__, T___RMUL__), HPY_TP_CALL(50, NO_TP_SLOT, HPySlotWrapper.CALL, T___CALL__), HPY_TP_HASH(59, NO_TP_SLOT, HPySlotWrapper.HASHFUNC, T___HASH__), HPY_TP_INIT(60, NO_TP_SLOT, HPySlotWrapper.INIT, T___INIT__), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyLegacyDef.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyLegacyDef.java index 79889912f5..c491d7d2ff 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyLegacyDef.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyLegacyDef.java @@ -197,10 +197,10 @@ enum HPyLegacySlot { Py_sq_concat(40, NO_TP_SLOT, T___ADD__), Py_sq_contains(41, NO_TP_SLOT, T___CONTAINS__, PExternalFunctionWrapper.OBJOBJPROC), Py_sq_inplace_concat(42, NO_TP_SLOT, T___IADD__), - Py_sq_inplace_repeat(43, NO_TP_SLOT, T___IMUL__, PExternalFunctionWrapper.ALLOC), + Py_sq_inplace_repeat(43, NO_TP_SLOT, T___IMUL__, PExternalFunctionWrapper.SSIZE_ARG), Py_sq_item(44, TpSlotMeta.SQ_ITEM, T___GETITEM__, PExternalFunctionWrapper.GETITEM), Py_sq_length(45, NO_TP_SLOT, T___LEN__, PExternalFunctionWrapper.LENFUNC), - Py_sq_repeat(46, NO_TP_SLOT, T___MUL__, PExternalFunctionWrapper.ALLOC), + Py_sq_repeat(46, NO_TP_SLOT, T___MUL__, PExternalFunctionWrapper.SSIZE_ARG), // PyAsyncMethods, NO_TP_SLOT Py_am_await(77, NO_TP_SLOT), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java index da1ece2e9d..a541d93bb6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java @@ -52,13 +52,11 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___HASH__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEG__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___POS__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___POW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RPOW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RSUB__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RTRUEDIV__; @@ -478,10 +476,9 @@ static PComplex doubleDivComplex(double left, PComplex right, PythonObjectFactor } } + @Slot(value = SlotKind.nb_multiply, isComplex = true) @GenerateNodeFactory - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) - abstract static class MulNode extends PythonBinaryBuiltinNode { + abstract static class MulNode extends BinaryOpBuiltinNode { @Specialization static Object doComplex(Object leftObj, Object rightObj, @Bind("this") Node inliningTarget, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java index 68997dd9ed..765ba88c0a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java @@ -64,12 +64,10 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REVERSED__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___SETITEM__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___HASH__; import static com.oracle.graal.python.nodes.StringLiterals.T_ELLIPSIS_IN_BRACKETS; @@ -96,8 +94,6 @@ import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeDelItemNodeClinicProviderGen; import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeInplaceMulNodeClinicProviderGen; import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeInsertNodeClinicProviderGen; -import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeMulNodeClinicProviderGen; -import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeRMulNodeClinicProviderGen; import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeRotateNodeClinicProviderGen; import com.oracle.graal.python.builtins.objects.deque.DequeBuiltinsClinicProviders.DequeSetItemNodeClinicProviderGen; import com.oracle.graal.python.builtins.objects.list.PList; @@ -107,6 +103,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.lib.GetNextNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.PyObjectGetIter; @@ -790,16 +787,9 @@ static PDeque doGeneric(Node node, PDeque self, int n) { } // deque.__mul__(v) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2, parameterNames = {"$self", "n"}) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory - @ArgumentClinic(name = "n", conversion = ClinicConversion.Index) - public abstract static class DequeMulNode extends PythonBinaryClinicBuiltinNode { - - @Override - protected ArgumentClinicProvider getArgumentClinic() { - return DequeMulNodeClinicProviderGen.INSTANCE; - } - + public abstract static class DequeMulNode extends SqRepeatBuiltinNode { @Specialization @TruffleBoundary PDeque doGeneric(PDeque self, int n) { @@ -810,17 +800,6 @@ PDeque doGeneric(PDeque self, int n) { } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2, parameterNames = {"$self", "n"}) - @GenerateNodeFactory - @ArgumentClinic(name = "n", conversion = ClinicConversion.Index) - public abstract static class DequeRMulNode extends DequeMulNode { - - @Override - protected ArgumentClinicProvider getArgumentClinic() { - return DequeRMulNodeClinicProviderGen.INSTANCE; - } - } - @Builtin(name = J___CONTAINS__, minNumOfPositionalArgs = 2) @GenerateNodeFactory public abstract static class DequeContainsNode extends PythonBinaryBuiltinNode { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java index 61c483459b..ee18afa692 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java @@ -45,7 +45,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEG__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___POS__; @@ -54,7 +53,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RFLOORDIV__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ROUND__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RPOW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RSUB__; @@ -351,8 +349,7 @@ protected Object op(double a, double b) { } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.nb_multiply, isComplex = true) @GenerateNodeFactory abstract static class MulNode extends AbstractNumericBinaryBuiltin { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java index 720e41dd24..45bbd06aef 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java @@ -27,7 +27,6 @@ package com.oracle.graal.python.builtins.objects.foreign; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError; -import static com.oracle.graal.python.builtins.PythonBuiltinClassType.MemoryError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; import static com.oracle.graal.python.builtins.objects.str.StringUtils.simpleTruffleStringFormatUncached; @@ -49,7 +48,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEXT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___OR__; @@ -57,7 +55,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RDIVMOD__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RFLOORDIV__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ROR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RSUB__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RTRUEDIV__; @@ -106,6 +103,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode; import com.oracle.graal.python.lib.PyNumberAddNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; +import com.oracle.graal.python.lib.PyNumberMultiplyNode; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; import com.oracle.graal.python.lib.PyObjectRichCompareBool; import com.oracle.graal.python.lib.PyObjectStrAsTruffleStringNode; @@ -127,7 +125,6 @@ import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.IsForeignObjectNode; import com.oracle.graal.python.nodes.util.CannotCastException; -import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext; import com.oracle.graal.python.runtime.GilNode; @@ -500,7 +497,7 @@ Object doArray(Object obj, @SuppressWarnings("unused") boolean doArray, @Shared @Cached(inline = false) PythonObjectFactory factory) { gil.release(true); try { - return factory.createTuple(unpackForeignArray(obj, lib, convert)); + return factory.createList(unpackForeignArray(obj, lib, convert)); } finally { gil.acquire(); } @@ -513,112 +510,58 @@ public static Object doGeneric(Object left, boolean doArray) { } } - @Slot(value = SlotKind.nb_add, isComplex = true) - @GenerateNodeFactory - abstract static class AddNode extends BinaryOpBuiltinNode { + @GenerateInline + @GenerateCached(false) + abstract static class ForeignBinarySlotNode extends Node { + abstract Object execute(VirtualFrame frame, Node inliningTarget, Object left, Object right, + boolean leftDoArray, boolean rightDoArray, BinaryOpNode binaryOpNode); + @Specialization - static Object doIt(VirtualFrame frame, Object left, Object right, - @Bind("this") Node inliningTarget, + static Object doIt(VirtualFrame frame, Node inliningTarget, Object left, Object right, + boolean leftDoArray, boolean rightDoArray, BinaryOpNode op, @Cached IsForeignObjectNode isForeignLeft, @Cached IsForeignObjectNode isForeignRight, @Cached NormalizeForeignForBinopNode normalizeLeft, - @Cached NormalizeForeignForBinopNode normalizeRight, - @Cached PyNumberAddNode addNode) { + @Cached NormalizeForeignForBinopNode normalizeRight) { boolean leftIsForeign = isForeignLeft.execute(inliningTarget, left); boolean rightIsForeign = isForeignRight.execute(inliningTarget, right); if (!leftIsForeign && !rightIsForeign) { return PNotImplemented.NOT_IMPLEMENTED; } - Object newLeft = normalizeLeft.execute(inliningTarget, left, true); - Object newRight = normalizeRight.execute(inliningTarget, right, true); + Object newLeft = normalizeLeft.execute(inliningTarget, left, leftDoArray); + Object newRight = normalizeRight.execute(inliningTarget, right, rightDoArray); assert newLeft == null || !IsForeignObjectNode.executeUncached(newLeft) : newLeft; assert newRight == null || !IsForeignObjectNode.executeUncached(newRight) : newRight; if (newLeft == null || newRight == null) { return PNotImplemented.NOT_IMPLEMENTED; } - return addNode.execute(frame, inliningTarget, newLeft, newRight); + return op.executeObject(frame, newLeft, newRight); } } - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.nb_add, isComplex = true) @GenerateNodeFactory - abstract static class MulNode extends ForeignBinaryNode { - MulNode() { - super(BinaryArithmetic.Mul.create(), false); - } - - @Specialization(insertBefore = "doComparisonBool", guards = {"!lib.isBoolean(left)", "!lib.isNumber(left)", "!lib.isString(left)", "lib.hasArrayElements(left)", "lib.fitsInLong(right)"}) - static Object doForeignArray(Object left, Object right, + abstract static class AddNode extends BinaryOpBuiltinNode { + @Specialization + static Object doIt(VirtualFrame frame, Object left, Object right, @Bind("this") Node inliningTarget, - @Shared @Cached PRaiseNode raise, - @Shared @Cached PythonObjectFactory factory, - @Shared @Cached PForeignToPTypeNode convert, - @Shared @CachedLibrary(limit = "3") InteropLibrary lib, - @Cached CastToJavaIntExactNode cast, - @Shared @Cached GilNode gil) { - gil.release(true); - try { - long rightLong; - try { - rightLong = lib.asLong(right); - } catch (UnsupportedMessageException e) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw new IllegalStateException("object does not unpack to index-sized int as it claims to"); - } - return doMulArray(left, cast.execute(inliningTarget, rightLong), raise, factory, convert, lib); - } finally { - gil.acquire(); - } - } - - @Specialization(insertBefore = "doComparisonBool", guards = {"!lib.isBoolean(left)", "!lib.isNumber(left)", "!lib.isString(left)", "lib.hasArrayElements(left)", "lib.isBoolean(right)"}) - static Object doForeignArrayForeignBoolean(Object left, Object right, - @Shared @Cached PRaiseNode raise, - @Shared @Cached PythonObjectFactory factory, - @Shared @Cached PForeignToPTypeNode convert, - @Shared @CachedLibrary(limit = "3") InteropLibrary lib, - @Shared @Cached GilNode gil) { - gil.release(true); - try { - boolean rightBoolean; - try { - rightBoolean = lib.asBoolean(right); - } catch (UnsupportedMessageException e) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw new IllegalStateException("object does not unpack to boolean (to be used as index) as it claims to"); - } - return doMulArray(left, rightBoolean ? 1 : 0, raise, factory, convert, lib); - } finally { - gil.acquire(); - } - } - - private static PythonAbstractObject doMulArray(Object left, int rightInt, PRaiseNode raise, PythonObjectFactory factory, PForeignToPTypeNode convert, InteropLibrary lib) { - try { - Object[] unpackForeignArray = unpackForeignArray(left, lib, convert); - if (unpackForeignArray != null) { - if (rightInt < 0) { - return factory.createList(); - } - Object[] repeatedData = new Object[Math.multiplyExact(unpackForeignArray.length, rightInt)]; - - for (int i = 0; i < rightInt; i++) { - System.arraycopy(unpackForeignArray, 0, repeatedData, i * unpackForeignArray.length, unpackForeignArray.length); - } - - return factory.createList(repeatedData); - } - return PNotImplemented.NOT_IMPLEMENTED; - } catch (ArithmeticException e) { - throw raise.raise(MemoryError); - } + @Cached ForeignBinarySlotNode binarySlotNode, + @Cached(inline = false) PyNumberAddNode addNode) { + return binarySlotNode.execute(frame, inliningTarget, left, right, true, true, addNode); } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.nb_multiply, isComplex = true) @GenerateNodeFactory - abstract static class RMulNode extends MulNode { + abstract static class MulNode extends BinaryOpBuiltinNode { + @Specialization + static Object doIt(VirtualFrame frame, Object left, Object right, + @Bind("this") Node inliningTarget, + @Cached ForeignBinarySlotNode binarySlotNode, + @Cached(inline = false) PyNumberMultiplyNode mulNode) { + return binarySlotNode.execute(frame, inliningTarget, left, right, true, true, mulNode); + } } @Builtin(name = J___SUB__, minNumOfPositionalArgs = 2) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java index 8d53e744d0..68ea65ac88 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java @@ -60,7 +60,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LSHIFT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEG__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___OR__; @@ -72,7 +71,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RFLOORDIV__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RLSHIFT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ROR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ROUND__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RPOW__; @@ -1036,11 +1034,10 @@ public static ModNode create() { } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.nb_multiply, isComplex = true) @GenerateNodeFactory @TypeSystemReference(PythonArithmeticTypes.class) - public abstract static class MulNode extends PythonBinaryBuiltinNode { + public abstract static class MulNode extends BinaryOpBuiltinNode { public abstract Object execute(int left, int right); @Specialization(rewriteOn = ArithmeticException.class) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java index 9ea858b05a..c4bd696b11 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java @@ -40,11 +40,9 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REVERSED__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___SETITEM__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___HASH__; import static com.oracle.graal.python.nodes.StringLiterals.T_COMMA_SPACE; @@ -93,6 +91,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.lib.PyIndexCheckNode; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; @@ -912,13 +911,11 @@ protected static SequenceStorageNodes.ExtendNode createExtend() { } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory - abstract static class MulNode extends PythonBinaryBuiltinNode { - + abstract static class MulNode extends SqRepeatBuiltinNode { @Specialization - static PList doPListInt(VirtualFrame frame, PList left, Object right, + static PList doPListInt(VirtualFrame frame, PList left, int right, @Bind("this") Node inliningTarget, @Cached SequenceStorageNodes.RepeatNode repeatNode, @Cached PythonObjectFactory factory, @@ -930,12 +927,6 @@ static PList doPListInt(VirtualFrame frame, PList left, Object right, throw raiseNode.get(inliningTarget).raise(MemoryError); } } - - @SuppressWarnings("unused") - @Fallback - static PNotImplemented doGeneric(Object left, Object right) { - return PNotImplemented.NOT_IMPLEMENTED; - } } @Builtin(name = J___IMUL__, minNumOfPositionalArgs = 2) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java index 2e4a4f2e3e..756e3b6b84 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java @@ -48,11 +48,9 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___STR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___TRUFFLE_RICHCOMPARE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___ADD__; @@ -134,6 +132,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.lib.PyIndexCheckNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.PyObjectGetItem; @@ -1851,11 +1850,10 @@ static Object doIt(VirtualFrame frame, Object selfObj, TruffleString encoding, T } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory @TypeSystemReference(PythonArithmeticTypes.class) - abstract static class MulNode extends PythonBinaryBuiltinNode { + abstract static class MulNode extends SqRepeatBuiltinNode { @Specialization(guards = "right <= 0") static TruffleString doStringIntNonPositive(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") int right) { @@ -1869,14 +1867,12 @@ static TruffleString doStringIntPositive(TruffleString left, int right, } @Specialization - static TruffleString doGeneric(VirtualFrame frame, Object self, Object rightObj, + static TruffleString doGeneric(Object self, int right, @Bind("this") Node inliningTarget, @Cached CastToTruffleStringCheckedNode castSelfNode, - @Cached PyNumberAsSizeNode asSizeNode, @Cached InlinedConditionProfile isNegativeProfile, @Shared("repeat") @Cached TruffleString.RepeatNode repeatNode) { TruffleString selfStr = castSelfNode.cast(inliningTarget, self, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, "index", self); - int right = asSizeNode.executeExact(frame, inliningTarget, rightObj); if (isNegativeProfile.profile(inliningTarget, right <= 0)) { return T_EMPTY_STRING; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java index ed9d157509..e4f66cd8fc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java @@ -35,10 +35,8 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NE__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___TRUFFLE_RICHCOMPARE__; import static com.oracle.graal.python.nodes.StringLiterals.T_COMMA; import static com.oracle.graal.python.nodes.StringLiterals.T_COMMA_SPACE; @@ -78,6 +76,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.LenBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqRepeatBuiltinNode; import com.oracle.graal.python.lib.PyIndexCheckNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.PyObjectHashNode; @@ -480,13 +479,12 @@ static Object doGeneric(@SuppressWarnings("unused") Object left, Object right, } } - @Builtin(name = J___RMUL__, minNumOfPositionalArgs = 2) - @Builtin(name = J___MUL__, minNumOfPositionalArgs = 2) + @Slot(value = SlotKind.sq_repeat, isComplex = true) @GenerateNodeFactory - abstract static class MulNode extends PythonBinaryBuiltinNode { + abstract static class MulNode extends SqRepeatBuiltinNode { @Specialization - static Object doTuple(VirtualFrame frame, Object left, Object right, + static Object doTuple(VirtualFrame frame, Object left, int repeats, @Bind("this") Node inliningTarget, @Cached PyTupleCheckExactNode checkTuple, @Cached GetTupleStorage getLeft, @@ -494,7 +492,6 @@ static Object doTuple(VirtualFrame frame, Object left, Object right, @Cached PyNumberAsSizeNode asSizeNode, @Cached SequenceStorageNodes.RepeatNode repeatNode, @Cached PythonObjectFactory.Lazy factory) { - int repeats = asSizeNode.executeExact(frame, inliningTarget, right); if (isSingleRepeat.profile(inliningTarget, repeats == 1 && checkTuple.execute(inliningTarget, left))) { return left; } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/SpecialMethodSlot.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/SpecialMethodSlot.java index d16dd1f87a..6b3089a4e3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/SpecialMethodSlot.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/SpecialMethodSlot.java @@ -54,7 +54,6 @@ import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_INT; import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_LSHIFT; import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_MATRIX_MULTIPLY; -import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_MULTIPLY; import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_OR; import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_POWER; import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_REMAINDER; @@ -102,7 +101,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MATMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MISSING__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEXT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NE__; @@ -116,7 +114,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RLSHIFT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RMATMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RMOD__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___ROR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___ROUND__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RPOW__; @@ -256,8 +253,6 @@ public enum SpecialMethodSlot { Sub(T___SUB__, NB_SUBTRACT), RSub(T___RSUB__, NB_SUBTRACT), // Don't add SQ_REPEAT, CPython doesn't add a wrapper for it - Mul(T___MUL__, NB_MULTIPLY), - RMul(T___RMUL__, NB_MULTIPLY), MatMul(T___MATMUL__, NB_MATRIX_MULTIPLY), RMatMul(T___RMATMUL__, NB_MATRIX_MULTIPLY), Mod(T___MOD__, NB_REMAINDER), @@ -331,7 +326,6 @@ static class Flags { And.reverse = RAnd; Or.reverse = ROr; Sub.reverse = RSub; - Mul.reverse = RMul; DivMod.reverse = RDivMod; TrueDiv.reverse = RTrueDiv; FloorDiv.reverse = RFloorDiv; @@ -1026,15 +1020,7 @@ public static SpecialMethodSlot findSpecialSlot(TruffleString name, TruffleStrin return RShift; } break; - case 'm' * 26 + 'u': // mu - if (eqNode.execute(name, T___MUL__, TS_ENCODING)) { - return Mul; - } - break; case 'r' * 26 + 'm': // rm - if (eqNode.execute(name, T___RMUL__, TS_ENCODING)) { - return RMul; - } if (eqNode.execute(name, T___RMATMUL__, TS_ENCODING)) { return RMatMul; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java index beb2016c17..5d0011cc73 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java @@ -49,7 +49,9 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___GETITEM__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___GET__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___LEN__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RADD__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RMUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SETATTR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SET__; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -198,9 +200,11 @@ */ public record TpSlots(TpSlot nb_bool, // TpSlot nb_add, + TpSlot nb_multiply, // TpSlot sq_length, // TpSlot sq_item, // TpSlot sq_concat, // + TpSlot sq_repeat, // TpSlot mp_length, // TpSlot mp_subscript, // TpSlot combined_sq_mp_length, // @@ -309,6 +313,14 @@ public enum TpSlotMeta { CFields.PyNumberMethods__nb_add, PExternalFunctionWrapper.BINARYFUNC, BinaryOpSlotFuncWrapper::createAdd), + NB_MULTIPLY( + TpSlots::nb_multiply, + TpSlotBinaryOpPython.class, + TpSlotBinaryOpBuiltin.class, + TpSlotGroup.AS_NUMBER, + CFields.PyNumberMethods__nb_multiply, + PExternalFunctionWrapper.BINARYFUNC, + BinaryOpSlotFuncWrapper::createMultiply), SQ_LENGTH( TpSlots::sq_length, TpSlotPythonSingle.class, @@ -333,6 +345,14 @@ public enum TpSlotMeta { CFields.PySequenceMethods__sq_item, PExternalFunctionWrapper.GETITEM, SsizeargfuncSlotWrapper::new), + SQ_REPEAT( + TpSlots::sq_repeat, + TpSlotPythonSingle.class, + TpSlotSizeArgFunBuiltin.class, + TpSlotGroup.AS_SEQUENCE, + CFields.PySequenceMethods__sq_repeat, + PExternalFunctionWrapper.SSIZE_ARG, + SsizeargfuncSlotWrapper::new), MP_LENGTH( TpSlots::mp_length, TpSlotPythonSingle.class, @@ -538,6 +558,10 @@ public static TpSlotDef withNoFunctionNoWrapper(TruffleString name) { public static TpSlotDef withNoFunction(TruffleString name, PExternalFunctionWrapper wrapper) { return new TpSlotDef(name, null, wrapper, null); } + + public static TpSlotDef withNoFunction(TruffleString name, PExternalFunctionWrapper wrapper, HPySlotWrapper hpyWrapper) { + return new TpSlotDef(name, null, wrapper, hpyWrapper); + } } /** @@ -575,11 +599,21 @@ private static void addSlotDef(LinkedHashMap defs, TpSl addSlotDef(s, TpSlotMeta.NB_ADD, TpSlotDef.withoutHPy(T___ADD__, TpSlotBinaryOpPython::create, PExternalFunctionWrapper.BINARYFUNC_L), TpSlotDef.withoutHPy(T___RADD__, TpSlotBinaryOpPython::create, PExternalFunctionWrapper.BINARYFUNC_R)); + addSlotDef(s, TpSlotMeta.NB_MULTIPLY, + TpSlotDef.withoutHPy(T___MUL__, TpSlotBinaryOpPython::create, PExternalFunctionWrapper.BINARYFUNC_L), + TpSlotDef.withoutHPy(T___RMUL__, TpSlotBinaryOpPython::create, PExternalFunctionWrapper.BINARYFUNC_R)); addSlotDef(s, TpSlotMeta.NB_BOOL, TpSlotDef.withSimpleFunction(T___BOOL__, PExternalFunctionWrapper.INQUIRY)); addSlotDef(s, TpSlotMeta.MP_LENGTH, TpSlotDef.withSimpleFunction(T___LEN__, PExternalFunctionWrapper.LENFUNC, HPySlotWrapper.LENFUNC)); addSlotDef(s, TpSlotMeta.MP_SUBSCRIPT, TpSlotDef.withSimpleFunction(T___GETITEM__, PExternalFunctionWrapper.BINARYFUNC, HPySlotWrapper.BINARYFUNC)); addSlotDef(s, TpSlotMeta.SQ_LENGTH, TpSlotDef.withSimpleFunction(T___LEN__, PExternalFunctionWrapper.LENFUNC, HPySlotWrapper.LENFUNC)); + // sq_concat does not have a slotdef for __radd__ unlike sq_repeat. This have consequences + // w.r.t. inheritance from native classes, where sq_repeat is not overridden by __mul__. + // Makes one wonder whether this CPython behavior is intended. + // see test_sq_repeat_mul_without_rmul_inheritance addSlotDef(s, TpSlotMeta.SQ_CONCAT, TpSlotDef.withNoFunction(T___ADD__, PExternalFunctionWrapper.BINARYFUNC)); + addSlotDef(s, TpSlotMeta.SQ_REPEAT, + TpSlotDef.withNoFunction(T___MUL__, PExternalFunctionWrapper.SSIZE_ARG, HPySlotWrapper.INDEXARGFUNC), + TpSlotDef.withNoFunction(T___RMUL__, PExternalFunctionWrapper.SSIZE_ARG, HPySlotWrapper.INDEXARGFUNC)); addSlotDef(s, TpSlotMeta.SQ_ITEM, TpSlotDef.withSimpleFunction(T___GETITEM__, PExternalFunctionWrapper.GETITEM, HPySlotWrapper.SQ_ITEM)); SLOTDEFS = s; @@ -1157,9 +1191,11 @@ public TpSlots build() { return new TpSlots( get(TpSlotMeta.NB_BOOL), // get(TpSlotMeta.NB_ADD), // + get(TpSlotMeta.NB_MULTIPLY), // get(TpSlotMeta.SQ_LENGTH), // get(TpSlotMeta.SQ_ITEM), // get(TpSlotMeta.SQ_CONCAT), // + get(TpSlotMeta.SQ_REPEAT), // get(TpSlotMeta.MP_LENGTH), // get(TpSlotMeta.MP_SUBSCRIPT), // sq_mp_length, // diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotBinaryOp.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotBinaryOp.java index 581a1386ad..f776aed79b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotBinaryOp.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotBinaryOp.java @@ -41,7 +41,9 @@ package com.oracle.graal.python.builtins.objects.type.slots; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___ADD__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___MUL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RADD__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.T___RMUL__; import java.util.Arrays; @@ -103,7 +105,8 @@ private TpSlotBinaryOp() { } public enum BinaryOpSlot { - NB_ADD(T___ADD__, T___RADD__); + NB_ADD(T___ADD__, T___RADD__), + NB_MULTIPLY(T___MUL__, T___RMUL__); private static final BinaryOpSlot[] VALUES = values(); private final TruffleString name; @@ -118,6 +121,7 @@ public TpSlot getSlotValue(TpSlots slots) { // switch instead of using TpSlotMeta for better inlining on fast-path return switch (this) { case NB_ADD -> slots.nb_add(); + case NB_MULTIPLY -> slots.nb_multiply(); }; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotSizeArgFun.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotSizeArgFun.java index cd66172bea..c7a26f57ef 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotSizeArgFun.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotSizeArgFun.java @@ -68,6 +68,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotPythonSingle; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotLen.CallSlotLenNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFunFactory.FixNegativeIndexNodeGen; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFunFactory.WrapIndexArgFuncBuiltinNodeGen; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFunFactory.WrapSqItemBuiltinNodeGen; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; @@ -118,7 +119,11 @@ public PBuiltinFunction createBuiltin(Python3Core core, Object type, TruffleStri return switch (wrapper) { case GETITEM -> createBuiltin(core, type, tsName, BuiltinSlotWrapperSignature.BINARY, wrapper, WrapperNodeFactory.wrap(getNodeFactory(), WrapSqItemBuiltinNode.class, WrapSqItemBuiltinNodeGen::create)); - default -> throw new IllegalStateException(Objects.toString(wrapper)); + case SSIZE_ARG -> createBuiltin(core, type, tsName, BuiltinSlotWrapperSignature.BINARY, wrapper, + WrapperNodeFactory.wrap(getNodeFactory(), WrapIndexArgFuncBuiltinNode.class, + WrapIndexArgFuncBuiltinNodeGen::create)); + default -> + throw new IllegalStateException(Objects.toString(wrapper)); }; } } @@ -140,12 +145,16 @@ public final Object execute(VirtualFrame frame, Object arg, Object arg2) { public abstract static class SqItemBuiltinNode extends SizeArgFunBuiltinNode { } + /** + * Implements semantics of {@code typeobject.c: wrap_sq_item}. + */ public abstract static class WrapSqItemBuiltinNode extends PythonBinaryBuiltinNode { - private @Child SizeArgFunBuiltinNode slotNode; + private @Child SqItemBuiltinNode slotNode; private @Child FixNegativeIndex fixNegativeIndex; protected WrapSqItemBuiltinNode(SizeArgFunBuiltinNode slotNode) { - this.slotNode = slotNode; + // We take SizeArgFunBuiltinNode just so that we can reuse WrapperNodeFactory machinery + this.slotNode = (SqItemBuiltinNode) slotNode; } @Specialization(guards = "index >= 0") @@ -170,6 +179,34 @@ Object doGeneric(VirtualFrame frame, Object self, Object index, } } + public abstract static class SqRepeatBuiltinNode extends SizeArgFunBuiltinNode { + } + + /** + * Implements semantics of {@code typeobject.c: wrap_indexargfunc}. + */ + public abstract static class WrapIndexArgFuncBuiltinNode extends PythonBinaryBuiltinNode { + private @Child SizeArgFunBuiltinNode slotNode; + + protected WrapIndexArgFuncBuiltinNode(SizeArgFunBuiltinNode slotNode) { + this.slotNode = slotNode; + } + + @Specialization(guards = "index >= 0") + Object doIntIndex(VirtualFrame frame, Object self, int index) { + return slotNode.execute(frame, self, index); + } + + @Specialization(replaces = "doIntIndex") + @SuppressWarnings("truffle-static-method") + Object doGeneric(VirtualFrame frame, Object self, Object index, + @Bind("this") Node inliningTarget, + @Cached PyNumberAsSizeNode asSizeNode) { + int size = asSizeNode.executeExact(frame, inliningTarget, index, PythonBuiltinClassType.OverflowError); + return slotNode.execute(frame, self, size); + } + } + @GenerateInline(false) // lazy public abstract static class FixNegativeIndex extends Node { public abstract int execute(VirtualFrame frame, int indexAsSize, Object indexObj); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberAddNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberAddNode.java index 35a0079a5a..483757851e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberAddNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberAddNode.java @@ -172,7 +172,6 @@ static Object doIt(VirtualFrame frame, Node inliningTarget, Object v, Object w, @Cached GetCachedTpSlotsNode getWSlots, @Exclusive @Cached GetClassNode getWClass, @Cached CallBinaryOp1Node callBinaryOp1Node, - @Cached InlinedBranchProfile hasNbAddSlot, @Cached InlinedBranchProfile hasNbAddResult, @Cached CallSlotBinaryFuncNode callBinarySlotNode, @Cached PRaiseNode.Lazy raiseNode) { @@ -183,7 +182,6 @@ static Object doIt(VirtualFrame frame, Node inliningTarget, Object v, Object w, TpSlot slotV = slotsV.nb_add(); TpSlot slotW = slotsW.nb_add(); if (slotV != null || slotW != null) { - hasNbAddSlot.enter(inliningTarget); Object result = callBinaryOp1Node.execute(frame, inliningTarget, v, classV, slotV, w, classW, slotW, BinaryOpSlot.NB_ADD); if (result != PNotImplemented.NOT_IMPLEMENTED) { hasNbAddResult.enter(inliningTarget); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberMultiplyNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberMultiplyNode.java new file mode 100644 index 0000000000..2f58fa3bce --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyNumberMultiplyNode.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.lib; + +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.objects.PNotImplemented; +import com.oracle.graal.python.builtins.objects.type.TpSlots; +import com.oracle.graal.python.builtins.objects.type.TpSlots.GetCachedTpSlotsNode; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlot; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryOp.BinaryOpSlot; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.CallSlotSizeArgFun; +import com.oracle.graal.python.nodes.ErrorMessages; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.PRaiseNode.Lazy; +import com.oracle.graal.python.nodes.expression.BinaryOpNode; +import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; + +@GenerateInline(inlineByDefault = true) +public abstract class PyNumberMultiplyNode extends BinaryOpNode { + public abstract Object execute(VirtualFrame frame, Node inliningTarget, Object v, Object w); + + @Override + public final Object executeObject(VirtualFrame frame, Object left, Object right) { + return executeCached(frame, left, right); + } + + public final Object executeCached(VirtualFrame frame, Object v, Object w) { + return execute(frame, this, v, w); + } + + public abstract int executeInt(VirtualFrame frame, Node inliningTarget, int left, int right) throws UnexpectedResultException; + + public abstract double executeDouble(VirtualFrame frame, Node inliningTarget, double left, double right) throws UnexpectedResultException; + + /* + * All the following fast paths need to be kept in sync with the corresponding builtin functions + * in IntBuiltins, FloatBuiltins, ListBuiltins, ... + */ + + @Specialization(rewriteOn = ArithmeticException.class) + public static int doII(int x, int y) throws ArithmeticException { + return Math.multiplyExact(x, y); + } + + @Specialization(replaces = "doII") + public static long doIIL(int x, int y) { + return x * (long) y; + } + + @Specialization(rewriteOn = ArithmeticException.class) + public static long doLL(long x, long y) { + return Math.multiplyExact(x, y); + } + + @Specialization + public static double doDL(double left, long right) { + return left * right; + } + + @Specialization + public static double doLD(long left, double right) { + return left * right; + } + + @Specialization + public static double doDD(double left, double right) { + return left * right; + } + + @Fallback + static Object doIt(VirtualFrame frame, Node inliningTarget, Object v, Object w, + @Exclusive @Cached GetClassNode getVClass, + @Cached GetCachedTpSlotsNode getVSlots, + @Cached GetCachedTpSlotsNode getWSlots, + @Exclusive @Cached GetClassNode getWClass, + @Cached CallBinaryOp1Node callBinaryOp1Node, + @Cached InlinedBranchProfile hasNbMulResult, + @Cached InlinedBranchProfile vHasSqRepeat, + @Cached InlinedBranchProfile wHasSqRepeat, + @Cached PyIndexCheckNode indexCheckNode, + @Cached PyNumberAsSizeNode asSizeNode, + @Cached CallSlotSizeArgFun callSlotNode, + @Cached PRaiseNode.Lazy raiseNode) { + Object classV = getVClass.execute(inliningTarget, v); + Object classW = getWClass.execute(inliningTarget, w); + TpSlots slotsV = getVSlots.execute(inliningTarget, classV); + TpSlots slotsW = getWSlots.execute(inliningTarget, classW); + TpSlot slotV = slotsV.nb_multiply(); + TpSlot slotW = slotsW.nb_multiply(); + if (slotV != null || slotW != null) { + Object result = callBinaryOp1Node.execute(frame, inliningTarget, v, classV, slotV, w, classW, slotW, BinaryOpSlot.NB_MULTIPLY); + if (result != PNotImplemented.NOT_IMPLEMENTED) { + hasNbMulResult.enter(inliningTarget); + return result; + } + } + if (slotsV.sq_repeat() != null) { + vHasSqRepeat.enter(inliningTarget); + return sequenceRepeat(frame, inliningTarget, slotsV.sq_repeat(), v, w, + indexCheckNode, asSizeNode, callSlotNode, raiseNode); + } else if (slotsW.sq_repeat() != null) { + wHasSqRepeat.enter(inliningTarget); + return sequenceRepeat(frame, inliningTarget, slotsW.sq_repeat(), w, v, + indexCheckNode, asSizeNode, callSlotNode, raiseNode); + } + return raiseNotSupported(inliningTarget, v, w, raiseNode); + } + + @InliningCutoff + private static PException raiseNotSupported(Node inliningTarget, Object v, Object w, Lazy raiseNode) { + return raiseNode.get(inliningTarget).raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P, "+", v, w); + } + + private static Object sequenceRepeat(VirtualFrame frame, Node inliningTarget, TpSlot slot, Object seq, Object n, + PyIndexCheckNode indexCheckNode, + PyNumberAsSizeNode asSizeNode, + CallSlotSizeArgFun callSlotNode, + PRaiseNode.Lazy raiseNode) { + if (indexCheckNode.execute(inliningTarget, n)) { + int count = asSizeNode.execute(frame, inliningTarget, n, PythonBuiltinClassType.OverflowError); + return callSlotNode.execute(frame, inliningTarget, slot, seq, count); + } else { + throw raiseNonIntSqMul(inliningTarget, n, raiseNode); + } + } + + @InliningCutoff + private static PException raiseNonIntSqMul(Node inliningTarget, Object n, Lazy raiseNode) { + throw raiseNode.get(inliningTarget).raise(PythonBuiltinClassType.TypeError, ErrorMessages.CANT_MULTIPLY_SEQ_BY_NON_INT, n); + } + + @NeverDefault + public static PyNumberMultiplyNode create() { + return PyNumberMultiplyNodeGen.create(); + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallBinaryNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallBinaryNode.java index fa817a6e7d..5831bc7937 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallBinaryNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallBinaryNode.java @@ -114,11 +114,6 @@ public static LookupAndCallBinaryNode createReversible(SpecialMethodSlot slot, S return LookupAndCallReversibleBinaryNodeGen.create(slot, rslot, handlerFactory, false, false); } - @NeverDefault - public static LookupAndCallBinaryNode createPyNumberMultiply(Supplier handlerFactory) { - return LookupAndCallNbNumbersBinaryNodeFactory.PyNumberMultiplyNodeGen.create(handlerFactory); - } - @NeverDefault public static LookupAndCallBinaryNode createBinaryOp(SpecialMethodSlot slot, SpecialMethodSlot rslot, Supplier handlerFactory) { return LookupAndCallNbNumbersBinaryNodeFactory.BinaryOpNodeGen.create(slot, rslot, handlerFactory); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallNbNumbersBinaryNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallNbNumbersBinaryNode.java index 9db0962784..935585a3fe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallNbNumbersBinaryNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallNbNumbersBinaryNode.java @@ -41,9 +41,7 @@ package com.oracle.graal.python.nodes.call.special; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; -import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.NB_MULTIPLY; import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.SLOT1BINFULL; -import static com.oracle.graal.python.builtins.objects.type.MethodsFlags.SQ_REPEAT; import static com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.graal.python.builtins.objects.PNone; @@ -83,83 +81,6 @@ private static Object lookupAttrId(VirtualFrame frame, Object obj, Object objCla return getattr.execute(frame, objClass, obj); } - // cpython://Objects/abstract.c#PyNumber_Multiply - protected abstract static class PyNumberMultiplyNode extends LookupAndCallNbNumbersBinaryNode { - PyNumberMultiplyNode(Supplier handlerFactory) { - super(handlerFactory); - } - - @Specialization(guards = {"left.getClass() == cachedLeftClass", "right.getClass() == cachedRightClass"}, limit = "5") - @SuppressWarnings("truffle-static-method") - Object mulC(VirtualFrame frame, Object left, Object right, - @Bind("this") Node inliningTarget, - @SuppressWarnings("unused") @Cached("left.getClass()") Class cachedLeftClass, - @SuppressWarnings("unused") @Cached("right.getClass()") Class cachedRightClass, - @Exclusive @Cached GetClassNode getClassNode, - @Exclusive @Cached("create(Mul)") LookupSpecialMethodSlotNode getattr, - @Exclusive @Cached GetMethodsFlagsNode getMethodsFlagsNode, - @Exclusive @Cached GetClassNode getlClassNode, - @Exclusive @Cached GetClassNode getrClassNode, - @Exclusive @Cached InlinedConditionProfile p1, - @Exclusive @Cached InlinedConditionProfile p2, - @Exclusive @Cached InlinedConditionProfile p3, - @Exclusive @Cached BinaryOp1Node binaryOp1Node, - @Exclusive @Cached Slot1BINFULLNode slot1BINFULLNode) { - return mul(frame, left, right, inliningTarget, getClassNode, getattr, getMethodsFlagsNode, getlClassNode, - getrClassNode, p1, p2, p3, binaryOp1Node, slot1BINFULLNode); - } - - @Specialization(replaces = "mulC") - @SuppressWarnings("truffle-static-method") - Object mul(VirtualFrame frame, Object left, Object right, - @Bind("this") Node inliningTarget, - @Exclusive @Cached GetClassNode getClassNode, - @Exclusive @Cached("create(Mul)") LookupSpecialMethodSlotNode getattr, - @Exclusive @Cached GetMethodsFlagsNode getMethodsFlagsNode, - @Exclusive @Cached GetClassNode getlClassNode, - @Exclusive @Cached GetClassNode getrClassNode, - @Exclusive @Cached InlinedConditionProfile p1, - @Exclusive @Cached InlinedConditionProfile p2, - @Exclusive @Cached InlinedConditionProfile p3, - @Exclusive @Cached BinaryOp1Node binaryOp1Node, - @Exclusive @Cached Slot1BINFULLNode slot1BINFULLNode) { - Object lClass = getlClassNode.execute(inliningTarget, left); - Object rClass = getrClassNode.execute(inliningTarget, right); - long lFlags = getMethodsFlagsNode.execute(inliningTarget, lClass); - long rFlags = getMethodsFlagsNode.execute(inliningTarget, rClass); - if (p1.profile(inliningTarget, ((lFlags | rFlags) & NB_MULTIPLY) != 0)) { - Object result; - SpecialMethodSlot slot = SpecialMethodSlot.Mul; - SpecialMethodSlot rslot = SpecialMethodSlot.RMul; - if (p2.profile(inliningTarget, BinaryOp1Node.isBothSLOT1BINFULL(lFlags, rFlags) || doSLOT1BINFULL(slot, lFlags, rFlags))) { - result = slot1BINFULLNode.execute(frame, left, right, slot, rslot, lFlags, rFlags, lClass, rClass); - } else { - result = binaryOp1Node.execute(frame, left, right, slot, rslot, lFlags, rFlags, lClass, rClass); - } - if (result != PNotImplemented.NOT_IMPLEMENTED) { - return result; - } - } - if (p3.profile(inliningTarget, ((lFlags | rFlags) & SQ_REPEAT) != 0)) { - Object seqObj = (lFlags & SQ_REPEAT) != 0 ? left : right; - Object seqClass = getClassNode.execute(inliningTarget, seqObj); - Object callable = getattr.execute(frame, seqClass, seqObj); - return ensureDispatch().executeObject(frame, callable, seqObj, seqObj == right ? left : right); - } - return runErrorHandler(frame, left, right); - } - - @Override - public TruffleString getName() { - return SpecialMethodSlot.Mul.getName(); - } - - @Override - public TruffleString getRname() { - return SpecialMethodSlot.RMul.getName(); - } - } - // cpython://Objects/abstract.c#binary_op protected abstract static class BinaryOpNode extends LookupAndCallNbNumbersBinaryNode { @@ -470,8 +391,7 @@ private static boolean maybeMissingSpecialization(Object result, SpecialMethodSl return result == PNotImplemented.NOT_IMPLEMENTED && otherSlot == PNone.NO_VALUE && lClass == rClass && - (slot == SpecialMethodSlot.Mul || - slot == SpecialMethodSlot.And || + (slot == SpecialMethodSlot.And || slot == SpecialMethodSlot.Or || slot == SpecialMethodSlot.Xor); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallReversibleBinaryNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallReversibleBinaryNode.java index 7c4ea536f2..35c3e04b9a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallReversibleBinaryNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallReversibleBinaryNode.java @@ -50,7 +50,6 @@ import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsSameTypeNode; import com.oracle.graal.python.nodes.ErrorMessages; -import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.GetClassNode; @@ -244,14 +243,19 @@ private Object dispatch(VirtualFrame frame, Node inliningTarget, CallBinaryMetho return dispatch.executeObject(frame, callable, leftValue, rightValue); } + @SuppressWarnings("unused") private static boolean isFlagSequenceCompat(Node inliningTarget, Object leftClass, Object rightClass, SpecialMethodSlot slot, InlinedBranchProfile gotLeftBuiltinClassType, InlinedBranchProfile gotRightBuiltinClassType) { + return false; + // Mul slot was converted to CPython like slots, this flag should never apply here + /*- if (PGuards.isNativeClass(leftClass) || PGuards.isNativeClass(rightClass)) { return false; } // see pypy descroperation.py#_make_binop_impl() boolean isSeqBugCompatOperation = (slot == SpecialMethodSlot.Mul); return isSeqBugCompatOperation && isFlagSequenceBugCompat(inliningTarget, leftClass, gotLeftBuiltinClassType) && !isFlagSequenceBugCompat(inliningTarget, rightClass, gotRightBuiltinClassType); + */ } private static boolean isFlagSequenceBugCompat(Node inliningTarget, Object clazz, InlinedBranchProfile gotBuiltinClassType) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryArithmetic.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryArithmetic.java index edc5897045..460af66496 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryArithmetic.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryArithmetic.java @@ -53,6 +53,7 @@ import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot; import com.oracle.graal.python.lib.PyNumberAddNode; +import com.oracle.graal.python.lib.PyNumberMultiplyNode; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.SpecialMethodNames; @@ -78,7 +79,7 @@ public enum BinaryArithmetic { Add(PyNumberAddNode::create), Sub(BinaryArithmeticFactory.SubNodeGen::create), - Mul(BinaryArithmeticFactory.MulNodeGen::create), + Mul(PyNumberMultiplyNode::create), TrueDiv(BinaryArithmeticFactory.TrueDivNodeGen::create), FloorDiv(BinaryArithmeticFactory.FloorDivNodeGen::create), Mod(BinaryArithmeticFactory.ModNodeGen::create), @@ -221,47 +222,6 @@ public static Object doGeneric(VirtualFrame frame, Object left, Object right, } } - public abstract static class MulNode extends BinaryArithmeticNode { - - public static final Supplier NOT_IMPLEMENTED = createHandler("*"); - - @Specialization(rewriteOn = ArithmeticException.class) - public static int doII(int x, int y) throws ArithmeticException { - return Math.multiplyExact(x, y); - } - - @Specialization(replaces = "doII") - public static long doIIL(int x, int y) { - return x * (long) y; - } - - @Specialization(rewriteOn = ArithmeticException.class) - public static long doLL(long x, long y) { - return Math.multiplyExact(x, y); - } - - @Specialization - public static double doDL(double left, long right) { - return left * right; - } - - @Specialization - public static double doLD(long left, double right) { - return left * right; - } - - @Specialization - public static double doDD(double left, double right) { - return left * right; - } - - @Specialization - public static Object doGeneric(VirtualFrame frame, Object left, Object right, - @Cached("createPyNumberMultiply(NOT_IMPLEMENTED)") LookupAndCallBinaryNode callNode) { - return callNode.executeObject(frame, left, right); - } - } - public abstract static class BinaryArithmeticRaiseNode extends BinaryArithmeticNode { protected static void raiseIntDivisionByZero(boolean cond, Node inliningTarget, PRaiseNode.Lazy raiseNode) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryOpNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryOpNode.java index 61ba63264c..f0b51431bd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryOpNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryOpNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -29,9 +29,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; public abstract class BinaryOpNode extends PNodeWithContext implements BinaryOp { - - // TODO: (tfel) refactor this method (executeWith) into a separate node. Right now this breaks - // the lengths we go to to avoid boxing :( @Override public abstract Object executeObject(VirtualFrame frame, Object left, Object right); } diff --git a/scripts/slot_fuzzer.py b/scripts/slot_fuzzer.py index 52ae384fa1..e9cb890365 100755 --- a/scripts/slot_fuzzer.py +++ b/scripts/slot_fuzzer.py @@ -65,6 +65,7 @@ import sys import re import traceback +import operator def slots_tester(Klass, other_klasses): def test(fun, name): try: @@ -153,8 +154,13 @@ def del_descr(self): del self.descr obj1 = Klass() test(lambda: obj1 + obj2, f"{Klass} + {type(obj2)}") test(lambda: obj2 + obj1, f"{type(obj2)} + {Klass}") + test(lambda: obj1 * obj2, f"{Klass} * {type(obj2)}") + test(lambda: obj2 * obj1, f"{type(obj2)} * {Klass}") + test(lambda: operator.concat(obj1, obj2), f"operator.concat({type(obj2)}, {Klass})") + test(lambda: operator.mul(obj1, obj2), f"operator.mul({type(obj2)}, {Klass})") test_dunder(obj1, "__add__", obj2) test_dunder(obj1, "__radd__", obj2) + test_dunder(obj1, "__mul__", obj2) ''' @@ -230,9 +236,11 @@ def tp_decl(self, name_prefix): SLOTS = [ Slot('tp_as_number', 'nb_bool', 'int $name$(PyObject* self)', ['1', '0', None]), Slot('tp_as_number', 'nb_add', 'PyObject* $name$(PyObject* self, PyObject *other)', ['Py_NewRef(self)', 'PyLong_FromLong(0)', None]), + Slot('tp_as_number', 'nb_multiply', 'PyObject* $name$(PyObject* self, PyObject *other)', ['Py_NewRef(self)', 'PyLong_FromLong(1)', None]), Slot('tp_as_sequence', 'sq_length', 'Py_ssize_t $name$(PyObject* self)', ['0', '1', '42', None]), Slot('tp_as_sequence', 'sq_item', 'PyObject* $name$(PyObject* self, Py_ssize_t index)', ['Py_NewRef(self)', 'PyLong_FromSsize_t(index + 1)', None]), Slot('tp_as_sequence', 'sq_concat', 'PyObject* $name$(PyObject* self, PyObject *other)', ['Py_NewRef(self)', 'PyLong_FromLong(10)', None]), + Slot('tp_as_sequence', 'sq_repeat', 'PyObject* $name$(PyObject* self, Py_ssize_t count)', ['Py_NewRef(self)', 'PyLong_FromLong(count)', None]), Slot('tp_as_mapping', 'mp_length', 'Py_ssize_t $name$(PyObject* self)', ['0', '1', '42', None]), Slot('tp_as_mapping', 'mp_subscript', 'PyObject* $name$(PyObject* self, PyObject* key)', ['Py_RETURN_FALSE', 'Py_NewRef(key)', None]), Slot(NO_GROUP, 'tp_getattr', 'PyObject* $name$(PyObject* self, char *name)', ['Py_RETURN_NONE', 'Py_RETURN_FALSE', 'Py_NewRef(self)', None, @@ -284,8 +292,9 @@ def tp_decl(self, name_prefix): MAGIC = { '__bool__(self)': ['True', 'False', None], - '__add__(self)': ['self', '"__add__result"', "NotImplemented", None], - '__radd__(self)': ['self', '"__add__result"', "NotImplemented", None], + '__add__(self, other)': ['self', '"__add__result"', "NotImplemented", "str(other)", None], + '__mul__(self, other)': ['self', '"__mul__result"', "NotImplemented", "repr(other)", None], + '__radd__(self, other)': ['self', '"__radd__result"', "NotImplemented", "'radd' + str(other)", None], '__len__(self)': ['0', '1', '42', None], '__getattribute__(self,name)': ['name', '42', 'global_dict1[name]', None], '__getattr__(self,name)': ['name+"abc"', 'False', 'global_dict1[name]', None],