Modules/xxclassloader.c (410 lines of code) (raw):

/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */ #include "Python.h" #include "classloader.h" #include "structmember.h" PyDoc_STRVAR(xxclassloader__doc__, "xxclassloader contains helpers for testing the class loader\n"); /* We link this module statically for convenience. If compiled as a shared library instead, some compilers don't allow addresses of Python objects defined in other libraries to be used in static initializers here. The DEFERRED_ADDRESS macro is used to tag the slots where such addresses appear; the module init function must fill in the tagged slots at runtime. The argument is for documentation -- the macro ignores it. */ #define DEFERRED_ADDRESS(ADDR) 0 /* spamobj -- a generic type*/ typedef struct { PyObject_HEAD PyObject *state; PyObject *str; Py_ssize_t val; size_t uval; } spamobject; static Py_ssize_t spamobj_error(spamobject *self, Py_ssize_t val) { if (val) { PyErr_SetString(PyExc_TypeError, "no way!"); return -1; } return 0; } static PyObject * spamobj_getstate(spamobject *self) { if (self->state) { Py_INCREF(self->state); return self->state; } Py_INCREF(Py_None); return Py_None; } static void spamobj_setstate(spamobject *self, PyObject *state) { Py_XDECREF(self->state); self->state = state; Py_INCREF(state); } static PyObject * spamobj_setstate_untyped(spamobject *self, PyObject *state) { if (!_PyClassLoader_CheckParamType((PyObject *)self, state, 0)) { PyErr_SetString(PyExc_TypeError, "bad type"); return NULL; } Py_XDECREF(self->state); self->state = state; Py_INCREF(state); Py_RETURN_NONE; } static void spamobj_setstate_optional(spamobject *self, PyObject *state) { if (state == Py_None) { return; } Py_XDECREF(self->state); self->state = state; Py_INCREF(state); } static void spamobj_setint(spamobject *self, Py_ssize_t val) { self->val = val; } static void spamobj_setint8(spamobject *self, int8_t val) { self->val = val; } static void spamobj_setint16(spamobject *self, int16_t val) { self->val = val; } static void spamobj_setint32(spamobject *self, int32_t val) { self->val = val; } static void spamobj_setuint8(spamobject *self, uint8_t val) { self->uval = val; } static void spamobj_setuint16(spamobject *self, uint16_t val) { self->uval = val; } static void spamobj_setuint32(spamobject *self, uint32_t val) { self->uval = val; } static void spamobj_setuint64(spamobject *self, uint64_t val) { self->uval = val; } static Py_ssize_t spamobj_twoargs(spamobject *self, Py_ssize_t x, Py_ssize_t y) { return x + y; } static Py_ssize_t spamobj_getint(spamobject *self) { return self->val; } static int8_t spamobj_getint8(spamobject *self) { return self->val; } static int16_t spamobj_getint16(spamobject *self) { return self->val; } static int32_t spamobj_getint32(spamobject *self) { return self->val; } static uint8_t spamobj_getuint8(spamobject *self) { return self->uval; } static uint16_t spamobj_getuint16(spamobject *self) { return self->uval; } static uint32_t spamobj_getuint32(spamobject *self) { return self->uval; } static uint64_t spamobj_getuint64(spamobject *self) { return self->uval; } static void spamobj_setstr(spamobject *self, PyObject *str) { Py_XDECREF(self->str); self->str = str; Py_INCREF(str); } static PyObject * spamobj_getstr(spamobject *self) { if (self->str == NULL) { Py_RETURN_NONE; } Py_INCREF(self->str); return self->str; } _Py_TYPED_SIGNATURE(spamobj_getstate, _Py_SIG_TYPE_PARAM_OPT(0), NULL); _Py_TYPED_SIGNATURE(spamobj_setstate, _Py_SIG_VOID, &_Py_Sig_T0, NULL); _Py_TYPED_SIGNATURE(spamobj_setstate_optional, _Py_SIG_VOID, &_Py_Sig_T0_Opt, NULL); _Py_TYPED_SIGNATURE(spamobj_getint, _Py_SIG_SSIZE_T, NULL); _Py_TYPED_SIGNATURE(spamobj_setint, _Py_SIG_VOID, &_Py_Sig_SSIZET, NULL); _Py_TYPED_SIGNATURE(spamobj_getuint64, _Py_SIG_SIZE_T, NULL); _Py_TYPED_SIGNATURE(spamobj_setuint64, _Py_SIG_VOID, &_Py_Sig_SIZET, NULL); _Py_TYPED_SIGNATURE(spamobj_getint8, _Py_SIG_INT8, NULL); _Py_TYPED_SIGNATURE(spamobj_setint8, _Py_SIG_VOID, &_Py_Sig_INT8, NULL); _Py_TYPED_SIGNATURE(spamobj_getint16, _Py_SIG_INT16, NULL); _Py_TYPED_SIGNATURE(spamobj_setint16, _Py_SIG_VOID, &_Py_Sig_INT16, NULL); _Py_TYPED_SIGNATURE(spamobj_getint32, _Py_SIG_INT32, NULL); _Py_TYPED_SIGNATURE(spamobj_setint32, _Py_SIG_VOID, &_Py_Sig_INT32, NULL); _Py_TYPED_SIGNATURE(spamobj_getuint8, _Py_SIG_UINT8, NULL); _Py_TYPED_SIGNATURE(spamobj_setuint8, _Py_SIG_VOID, &_Py_Sig_UINT8, NULL); _Py_TYPED_SIGNATURE(spamobj_getuint16, _Py_SIG_UINT16, NULL); _Py_TYPED_SIGNATURE(spamobj_setuint16, _Py_SIG_VOID, &_Py_Sig_UINT16, NULL); _Py_TYPED_SIGNATURE(spamobj_getuint32, _Py_SIG_UINT32, NULL); _Py_TYPED_SIGNATURE(spamobj_setuint32, _Py_SIG_VOID, &_Py_Sig_UINT32, NULL); _Py_TYPED_SIGNATURE(spamobj_getstr, _Py_SIG_STRING, NULL); _Py_TYPED_SIGNATURE(spamobj_setstr, _Py_SIG_VOID, &_Py_Sig_String, NULL); _Py_TYPED_SIGNATURE( spamobj_twoargs, _Py_SIG_SSIZE_T, &_Py_Sig_SSIZET, &_Py_Sig_SSIZET, NULL); _Py_TYPED_SIGNATURE( spamobj_error, _Py_SIG_ERROR, &_Py_Sig_SSIZET,NULL); static PyMethodDef spamobj_methods[] = { {"error", (PyCFunction)&spamobj_error_def, METH_TYPED, PyDoc_STR("error() -> raises")}, {"getstate", (PyCFunction)&spamobj_getstate_def, METH_TYPED, PyDoc_STR("getstate() -> state")}, {"setstate", (PyCFunction)&spamobj_setstate_def, METH_TYPED, PyDoc_STR("setstate(state)")}, {"setstate_untyped", (PyCFunction)&spamobj_setstate_untyped, METH_O, PyDoc_STR("setstate(state)")}, {"setstateoptional", (PyCFunction)&spamobj_setstate_optional_def, METH_TYPED, PyDoc_STR("setstate(state|None)")}, {"getint", (PyCFunction)&spamobj_getint_def, METH_TYPED, PyDoc_STR("getint() -> i")}, {"setint", (PyCFunction)&spamobj_setint_def, METH_TYPED, PyDoc_STR("setint(i)")}, {"getint8", (PyCFunction)&spamobj_getint8_def, METH_TYPED, PyDoc_STR("getint8() -> i")}, {"setint8", (PyCFunction)&spamobj_setint8_def, METH_TYPED, PyDoc_STR("setint8(i)")}, {"getint16", (PyCFunction)&spamobj_getint16_def, METH_TYPED, PyDoc_STR("getint16() -> i")}, {"setint16", (PyCFunction)&spamobj_setint16_def, METH_TYPED, PyDoc_STR("setint16(i)")}, {"getint32", (PyCFunction)&spamobj_getint32_def, METH_TYPED, PyDoc_STR("getint32() -> i")}, {"setint32", (PyCFunction)&spamobj_setint32_def, METH_TYPED, PyDoc_STR("setint32(i)")}, {"getuint8", (PyCFunction)&spamobj_getuint8_def, METH_TYPED, PyDoc_STR("getuint8() -> i")}, {"setuint8", (PyCFunction)&spamobj_setuint8_def, METH_TYPED, PyDoc_STR("setuint8(i)")}, {"getuint16", (PyCFunction)&spamobj_getuint16_def, METH_TYPED, PyDoc_STR("getuint16() -> i")}, {"setuint16", (PyCFunction)&spamobj_setuint16_def, METH_TYPED, PyDoc_STR("setuint16(i)")}, {"getuint32", (PyCFunction)&spamobj_getuint32_def, METH_TYPED, PyDoc_STR("getuint32() -> i")}, {"setuint32", (PyCFunction)&spamobj_setuint32_def, METH_TYPED, PyDoc_STR("setuint32(i)")}, {"getuint64", (PyCFunction)&spamobj_getuint64_def, METH_TYPED, PyDoc_STR("getuint64() -> i")}, {"setuint64", (PyCFunction)&spamobj_setuint64_def, METH_TYPED, PyDoc_STR("setuint64(i)")}, {"getstr", (PyCFunction)&spamobj_getstr_def, METH_TYPED, PyDoc_STR("getstr() -> s")}, {"setstr", (PyCFunction)&spamobj_setstr_def, METH_TYPED, PyDoc_STR("setstr(s)")}, {"twoargs", (PyCFunction)&spamobj_twoargs_def, METH_TYPED, PyDoc_STR("twoargs(s)")}, {"__class_getitem__", (PyCFunction)_PyClassLoader_GtdGetItem, METH_VARARGS | METH_CLASS, NULL}, {NULL, NULL}, }; static int spamobj_traverse(spamobject *o, visitproc visit, void *arg) { Py_VISIT(o->state); return 0; } static int spamobj_clear(spamobject *o) { Py_CLEAR(o->state); return 0; } static void spamobj_dealloc(spamobject *o) { PyObject_GC_UnTrack(o); Py_XDECREF(o->state); Py_XDECREF(o->str); Py_TYPE(o)->tp_free(o); } _PyGenericTypeDef spamobj_type = { .gtd_type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "spamobj[T]", sizeof(spamobject), 0, (destructor)spamobj_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_GENERIC_TYPE_DEF, /* tp_flags */ 0, /* tp_doc */ (traverseproc)spamobj_traverse, /* tp_traverse */ (inquiry)spamobj_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ spamobj_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ 0, /* tp_new */ PyObject_GC_Del, /* tp_free */ }, .gtd_size = 1, .gtd_new = PyType_GenericNew, }; static int xxclassloader_exec(PyObject *m) { /* Fill in deferred data addresses. This must be done before PyType_Ready() is called. Note that PyType_Ready() automatically initializes the ob.ob_type field to &PyType_Type if it's NULL, so it's not necessary to fill in ob_type first. */ if (PyType_Ready((PyTypeObject *)&spamobj_type) < 0) return -1; Py_INCREF(&spamobj_type); if (PyModule_AddObject(m, "spamobj", (PyObject *)&spamobj_type) < 0) return -1; return 0; } static struct PyModuleDef_Slot xxclassloader_slots[] = { {Py_mod_exec, xxclassloader_exec}, {0, NULL}, }; static int64_t xxclassloader_foo(PyObject *self) { return 42; } _Py_TYPED_SIGNATURE(xxclassloader_foo, _Py_SIG_INT64, NULL); static int64_t xxclassloader_bar(PyObject *self, int64_t f) { return f; } _Py_TYPED_SIGNATURE(xxclassloader_bar, _Py_SIG_INT64, &_Py_Sig_SIZET, NULL); static int64_t xxclassloader_neg(PyObject *self) { return -1; } _Py_TYPED_SIGNATURE(xxclassloader_neg, _Py_SIG_INT64, NULL); static PyMethodDef xxclassloader_methods[] = { {"foo", (PyCFunction)&xxclassloader_foo_def, METH_TYPED, ""}, {"bar", (PyCFunction)&xxclassloader_bar_def, METH_TYPED, ""}, {"neg", (PyCFunction)&xxclassloader_neg_def, METH_TYPED, ""}, {} }; static struct PyModuleDef xxclassloadermodule = {PyModuleDef_HEAD_INIT, "xxclassloader", xxclassloader__doc__, 0, xxclassloader_methods, xxclassloader_slots, NULL, NULL, NULL}; PyMODINIT_FUNC PyInit_xxclassloader(void) { return PyModuleDef_Init(&xxclassloadermodule); }