| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -143,6 +143,11 @@ typedef struct { | |||
| 143 | 143 | * backwards-compatibility */ | |
| 144 | 144 | typedef Py_ssize_t printfunc; | |
| 145 | 145 | ||
| 146 | + /* Specialize a binary op by setting the descriptor pointer */ | ||
| 147 | + struct _PyBinopSpecializationDescr; | ||
| 148 | + typedef int (*binop_specialize_func)(PyObject *v, PyObject *w, int oparg, | ||
| 149 | + struct _PyBinopSpecializationDescr **descr); | ||
| 150 | + | ||
| 146 | 151 | // If this structure is modified, Doc/includes/typestruct.h should be updated | |
| 147 | 152 | // as well. | |
| 148 | 153 | struct _typeobject { | |
@@ -233,6 +238,13 @@ struct _typeobject { | |||
| 233 | 238 | /* bitset of which type-watchers care about this type */ | |
| 234 | 239 | unsigned char tp_watched; | |
| 235 | 240 | ||
| 241 | + /* callback that may specialize BINARY_OP | ||
| 242 | + * this is an experimental API based on the ideas in the paper | ||
| 243 | + * Cross Module Quickening - The Curious Case of C Extensions | ||
| 244 | + * by Felix Berlakovich and Stefan Brunthaler. | ||
| 245 | + */ | ||
| 246 | + binop_specialize_func tp_binop_specialize; | ||
| 247 | + | ||
| 236 | 248 | /* Number of tp_version_tag values used. | |
| 237 | 249 | * Set to _Py_ATTR_CACHE_UNUSED if the attribute cache is | |
| 238 | 250 | * disabled for this type (e.g. due to custom MRO entries). | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -482,13 +482,18 @@ adaptive_counter_backoff(_Py_BackoffCounter counter) { | |||
| 482 | 482 | /* Specialization Extensions */ | |
| 483 | 483 | ||
| 484 | 484 | /* callbacks for an external specialization */ | |
| 485 | + | ||
| 486 | + struct _PyBinopSpecializationDescr; | ||
| 487 | + | ||
| 485 | 488 | typedef int (*binaryopguardfunc)(PyObject *lhs, PyObject *rhs); | |
| 486 | - typedef PyObject *(*binaryopactionfunc)(PyObject *lhs, PyObject *rhs); | ||
| 489 | + typedef PyObject* (*binaryopactionfunc)(PyObject *lhs, PyObject *rhs); | ||
| 490 | + typedef void (*binaryopfreefunc)(struct _PyBinopSpecializationDescr *descr); | ||
| 487 | 491 | ||
| 488 | - typedef struct { | ||
| 492 | + typedef struct _PyBinopSpecializationDescr { | ||
| 489 | 493 | int oparg; | |
| 490 | 494 | binaryopguardfunc guard; | |
| 491 | 495 | binaryopactionfunc action; | |
| 496 | + binaryopfreefunc free; | ||
| 492 | 497 | } _PyBinaryOpSpecializationDescr; | |
| 493 | 498 | ||
| 494 | 499 | /* Comparison bit masks. */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -93,4 +93,5 @@ | |||
| 93 | 93 | #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030E0000 | |
| 94 | 94 | /* New in 3.14 */ | |
| 95 | 95 | #define Py_tp_token 83 | |
| 96 | + #define Py_tp_binop_specialize 84 | ||
| 96 | 97 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1776,7 +1776,7 @@ def delx(self): del self.__x | |||
| 1776 | 1776 | check((1,2,3), vsize('') + self.P + 3*self.P) | |
| 1777 | 1777 | # type | |
| 1778 | 1778 | # static type: PyTypeObject | |
| 1779 | - fmt = 'P2nPI13Pl4Pn9Pn12PIPc' | ||
| 1779 | + fmt = 'P2nPI13Pl4Pn9Pn12PI3Pc' | ||
| 1780 | 1780 | s = vsize(fmt) | |
| 1781 | 1781 | check(int, s) | |
| 1782 | 1782 | typeid = 'n' if support.Py_GIL_DISABLED else '' | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Add option for extension modules to specialize ``BINARY_OP`` instructions. | ||
| 2 | + Applied to ``array`` objects. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,6 +14,8 @@ | |||
| 14 | 14 | #include "pycore_modsupport.h" // _PyArg_NoKeywords() | |
| 15 | 15 | #include "pycore_moduleobject.h" // _PyModule_GetState() | |
| 16 | 16 | ||
| 17 | + #include "opcode.h" // binary op opargs (NB_*) | ||
| 18 | + | ||
| 17 | 19 | #include <stddef.h> // offsetof() | |
| 18 | 20 | #include <stdbool.h> | |
| 19 | 21 | ||
@@ -848,6 +850,10 @@ array_richcompare(PyObject *v, PyObject *w, int op) | |||
| 848 | 850 | return res; | |
| 849 | 851 | } | |
| 850 | 852 | ||
| 853 | + static int | ||
| 854 | + array_binop_specialize(PyObject *v, PyObject *w, int oparg, | ||
| 855 | + _PyBinaryOpSpecializationDescr **descr); | ||
| 856 | + | ||
| 851 | 857 | static Py_ssize_t | |
| 852 | 858 | array_length(PyObject *op) | |
| 853 | 859 | { | |
@@ -2963,6 +2969,8 @@ static PyType_Slot array_slots[] = { | |||
| 2963 | 2969 | {Py_tp_alloc, PyType_GenericAlloc}, | |
| 2964 | 2970 | {Py_tp_new, array_new}, | |
| 2965 | 2971 | {Py_tp_traverse, array_tp_traverse}, | |
| 2972 | + {Py_tp_token, Py_TP_USE_SPEC}, | ||
| 2973 | + {Py_tp_binop_specialize, array_binop_specialize}, | ||
| 2966 | 2974 | ||
| 2967 | 2975 | /* as sequence */ | |
| 2968 | 2976 | {Py_sq_length, array_length}, | |
@@ -2995,6 +3003,70 @@ static PyType_Spec array_spec = { | |||
| 2995 | 3003 | .slots = array_slots, | |
| 2996 | 3004 | }; | |
| 2997 | 3005 | ||
| 3006 | + static inline int | ||
| 3007 | + array_subscr_guard(PyObject *lhs, PyObject *rhs) | ||
| 3008 | + { | ||
| 3009 | + PyObject *exc = PyErr_GetRaisedException(); | ||
| 3010 | + int ret = PyType_GetBaseByToken(Py_TYPE(lhs), &array_spec, NULL); | ||
| 3011 | + if (ret < 0) { | ||
| 3012 | + if (PyErr_ExceptionMatches(PyExc_TypeError)) { | ||
| 3013 | + PyErr_Clear(); | ||
| 3014 | + ret = 0; | ||
| 3015 | + } | ||
| 3016 | + } | ||
| 3017 | + _PyErr_ChainExceptions1(exc); | ||
| 3018 | + return ret; | ||
| 3019 | + } | ||
| 3020 | + | ||
| 3021 | + static PyObject * | ||
| 3022 | + array_subscr_action(PyObject *lhs, PyObject *rhs) | ||
| 3023 | + { | ||
| 3024 | + return array_subscr(lhs, rhs); | ||
| 3025 | + } | ||
| 3026 | + | ||
| 3027 | + static void | ||
| 3028 | + array_subscr_free(_PyBinaryOpSpecializationDescr* descr) | ||
| 3029 | + { | ||
| 3030 | + if (descr != NULL) { | ||
| 3031 | + PyMem_Free(descr); | ||
| 3032 | + } | ||
| 3033 | + } | ||
| 3034 | + | ||
| 3035 | + static int | ||
| 3036 | + array_binop_specialize(PyObject *v, PyObject *w, int oparg, | ||
| 3037 | + _PyBinaryOpSpecializationDescr **descr) | ||
| 3038 | + { | ||
| 3039 | + array_state *state = find_array_state_by_type(Py_TYPE(v)); | ||
| 3040 | + | ||
| 3041 | + if (!array_Check(v, state)) { | ||
| 3042 | + return 0; | ||
| 3043 | + } | ||
| 3044 | + | ||
| 3045 | + *descr = NULL; | ||
| 3046 | + switch(oparg) { | ||
| 3047 | + case NB_SUBSCR: | ||
| 3048 | + if (array_subscr_guard(v, w)) { | ||
| 3049 | + *descr = (_PyBinaryOpSpecializationDescr*)PyMem_Malloc( | ||
| 3050 | + sizeof(_PyBinaryOpSpecializationDescr)); | ||
| 3051 | + if (*descr == NULL) { | ||
| 3052 | + PyErr_NoMemory(); | ||
| 3053 | + return -1; | ||
| 3054 | + } | ||
| 3055 | + **descr = (_PyBinaryOpSpecializationDescr) { | ||
| 3056 | + .oparg = oparg, | ||
| 3057 | + .guard = array_subscr_guard, | ||
| 3058 | + .action = array_subscr_action, | ||
| 3059 | + .free = array_subscr_free, | ||
| 3060 | + }; | ||
| 3061 | + return 1; | ||
| 3062 | + } | ||
| 3063 | + break; | ||
| 3064 | + } | ||
| 3065 | + | ||
| 3066 | + return 0; | ||
| 3067 | + } | ||
| 3068 | + | ||
| 3069 | + | ||
| 2998 | 3070 | /*********************** Array Iterator **************************/ | |
| 2999 | 3071 | ||
| 3000 | 3072 | /*[clinic input] | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -801,9 +801,19 @@ dummy_func( | |||
| 801 | 801 | PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); | |
| 802 | 802 | _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; | |
| 803 | 803 | assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); | |
| 804 | - assert(d && d->guard); | ||
| 804 | + assert(d); | ||
| 805 | + assert(d->guard); | ||
| 805 | 806 | int res = d->guard(left_o, right_o); | |
| 806 | - DEOPT_IF(!res); | ||
| 807 | + ERROR_IF(res < 0); | ||
| 808 | + if (res == 0) { | ||
| 809 | + if (d->free) { | ||
| 810 | + d->free(d); | ||
| 811 | + } | ||
| 812 | + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(this_instr+1); | ||
| 813 | + write_ptr(cache->external_cache, NULL); | ||
| 814 | + this_instr->op.code = BINARY_OP; | ||
| 815 | + DEOPT_IF(true); | ||
| 816 | + } | ||
| 807 | 817 | } | |
| 808 | 818 | ||
| 809 | 819 | pure op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) { | |
@@ -816,6 +826,7 @@ dummy_func( | |||
| 816 | 826 | ||
| 817 | 827 | PyObject *res_o = d->action(left_o, right_o); | |
| 818 | 828 | DECREF_INPUTS(); | |
| 829 | + ERROR_IF(res_o == NULL); | ||
| 819 | 830 | res = PyStackRef_FromPyObjectSteal(res_o); | |
| 820 | 831 | } | |
| 821 | 832 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments