diff --git a/.gitignore b/.gitignore index 4978ee2cf..5bbe6c8c7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ hpy/tools/autogen/autogen_pypy.txt hpy/devel/include/common/version.h hpy/devel/version.py +# stubs created by setup.py when doing build_ext --inplace +proof-of-concept/pof.py +proof-of-concept/pofpackage/foo.py + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/Makefile b/Makefile index 15357f7b2..23ae60ff5 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ -all: +.PHONY: all +all: hpy.universal + +.PHONY: hpy.universal +hpy.universal: python3 setup.py build_ext -if debug: - HPY_DEBUG=1 python3 setup.py build_ext -if + HPY_DEBUG=1 make all autogen: python3 -m hpy.tools.autogen . @@ -15,7 +19,7 @@ cppcheck: cppcheck-build-dir infer: python3 setup.py build_ext -if -U NDEBUG | compiledb - @infer --fail-on-issue --compilation-database compile_commands.json + @infer --fail-on-issue --compilation-database compile_commands.json --report-blacklist-path-regex "hpy/debug/src/debug_ctx.c" valgrind: PYTHONMALLOC=malloc valgrind --suppressions=hpy/tools/valgrind/python.supp --suppressions=hpy/tools/valgrind/hpy.supp --leak-check=full --show-leak-kinds=definite,indirect --log-file=/tmp/valgrind-output python -m pytest --valgrind --valgrind-log=/tmp/valgrind-output test/ diff --git a/hpy/debug/__init__.py b/hpy/debug/__init__.py new file mode 100644 index 000000000..ae5bff69e --- /dev/null +++ b/hpy/debug/__init__.py @@ -0,0 +1 @@ +from .leakdetector import HPyError, HPyLeak, LeakDetector diff --git a/hpy/debug/leakdetector.py b/hpy/debug/leakdetector.py new file mode 100644 index 000000000..38f521075 --- /dev/null +++ b/hpy/debug/leakdetector.py @@ -0,0 +1,41 @@ +from hpy.universal import _debug + +class HPyError(Exception): + pass + +class HPyLeak(HPyError): + def __init__(self, leaks): + super().__init__() + self.leaks = leaks + + def __str__(self): + lines = [] + lines.append('%s handles have not been closed properly:' % len(self.leaks)) + for dh in self.leaks: + lines.append(' %r' % dh) + return '\n'.join(lines) + + +class LeakDetector: + + def __init__(self): + self.generation = None + + def start(self): + if self.generation is not None: + raise ValueError('LeakDetector already started') + self.generation = _debug.new_generation() + + def stop(self): + if self.generation is None: + raise ValueError('LeakDetector not started yet') + leaks = _debug.get_open_handles(self.generation) + if leaks: + raise HPyLeak(leaks) + + def __enter__(self): + self.start() + return self + + def __exit__(self, etype, evalue, tb): + self.stop() diff --git a/hpy/debug/src/_debugmod.c b/hpy/debug/src/_debugmod.c new file mode 100644 index 000000000..4f59d734b --- /dev/null +++ b/hpy/debug/src/_debugmod.c @@ -0,0 +1,212 @@ +// Python-level interface for the _debug module. Written in HPy itself, the +// idea is that it should be reusable by other implementations + +// NOTE: hpy.debug._debug is loaded using the UNIVERSAL ctx. To make it +// clearer, we will use "uctx" and "dctx" to distinguish them. + +#include "hpy.h" +#include "debug_internal.h" + +static UHPy new_DebugHandleObj(HPyContext uctx, UHPy u_DebugHandleType, + DebugHandle *handle); + + +HPyDef_METH(new_generation, "new_generation", new_generation_impl, HPyFunc_NOARGS) +static UHPy new_generation_impl(HPyContext uctx, UHPy self) +{ + HPyContext dctx = hpy_debug_get_ctx(uctx); + HPyDebugInfo *info = get_info(dctx); + info->current_generation++; + return HPyLong_FromLong(uctx, info->current_generation); +} + + +HPyDef_METH(get_open_handles, "get_open_handles", get_open_handles_impl, HPyFunc_O, .doc= + "Return a list containing all the open handles whose generation is >= " + "of the given arg") +static UHPy get_open_handles_impl(HPyContext uctx, UHPy u_self, UHPy u_gen) +{ + HPyContext dctx = hpy_debug_get_ctx(uctx); + HPyDebugInfo *info = get_info(dctx); + + UHPy u_DebugHandleType = HPy_GetAttr_s(uctx, u_self, "DebugHandle"); + if (HPy_IsNull(u_DebugHandleType)) + return HPy_NULL; + + long gen = HPyLong_AsLong(uctx, u_gen); + if (HPyErr_Occurred(uctx)) + return HPy_NULL; + + UHPy u_result = HPyList_New(uctx, 0); + if (HPy_IsNull(u_result)) + return HPy_NULL; + + DebugHandle *dh = info->open_handles; + while(dh != NULL) { + if (dh->generation >= gen) { + UHPy u_item = new_DebugHandleObj(uctx, u_DebugHandleType, dh); + if (HPy_IsNull(u_item)) + return HPy_NULL; + if (HPyList_Append(uctx, u_result, u_item) == -1) { + HPy_Close(uctx, u_item); + HPy_Close(uctx, u_result); + return HPy_NULL; + } + HPy_Close(uctx, u_item); + } + dh = dh->next; + } + return u_result; +} + +/* ~~~~~~ DebugHandleType and DebugHandleObject ~~~~~~~~ + + This is the applevel view of a DebugHandle/DHPy. + + Note that there are two different ways to expose DebugHandle to applevel: + + 1. make DebugHandle itself a Python object: this is simple but means that + you have to pay the PyObject_HEAD overhead (16 bytes) for all of them + + 2. make DebugHandle a plain C struct, and expose them through a + Python-level wrapper. + + We choose to implement solution 2 because we expect to have many + DebugHandle around, but to expose only few of them to applevel, when you + call get_open_handles. This way, we save 16 bytes per DebugHandle. + + This means that you can have different DebugHandleObjects wrapping the same + DebugHandle. To make it easier to compare them, they expose the .id + attribute, which is the address of the wrapped DebugHandle. Also, + DebugHandleObjects compare equal if their .id is equal. +*/ + +typedef struct { + HPyObject_HEAD + DebugHandle *handle; +} DebugHandleObject; + +HPyDef_GET(DebugHandle_obj, "obj", DebugHandle_obj_get, + .doc="The object which the handle points to") +static UHPy DebugHandle_obj_get(HPyContext uctx, UHPy self, void *closure) +{ + DebugHandleObject *dh = HPy_CAST(uctx, DebugHandleObject, self); + return HPy_Dup(uctx, dh->handle->uh); +} + +HPyDef_GET(DebugHandle_id, "id", DebugHandle_id_get, + .doc="A numeric identifier representing the underlying universal handle") +static UHPy DebugHandle_id_get(HPyContext uctx, UHPy self, void *closure) +{ + DebugHandleObject *dh = HPy_CAST(uctx, DebugHandleObject, self); + return HPyLong_FromSsize_t(uctx, (HPy_ssize_t)dh->handle); +} + +HPyDef_SLOT(DebugHandle_cmp, DebugHandle_cmp_impl, HPy_tp_richcompare) +static UHPy DebugHandle_cmp_impl(HPyContext uctx, UHPy self, UHPy o, HPy_RichCmpOp op) +{ + UHPy T = HPy_Type(uctx, self); + if (!HPy_TypeCheck(uctx, o, T)) + return HPy_Dup(uctx, uctx->h_NotImplemented); + DebugHandleObject *dh_self = HPy_CAST(uctx, DebugHandleObject, self); + DebugHandleObject *dh_o = HPy_CAST(uctx, DebugHandleObject, o); + + switch(op) { + case HPy_EQ: + return HPyBool_FromLong(uctx, dh_self->handle == dh_o->handle); + case HPy_NE: + return HPyBool_FromLong(uctx, dh_self->handle != dh_o->handle); + default: + return HPy_Dup(uctx, uctx->h_NotImplemented); + } +} + +HPyDef_SLOT(DebugHandle_repr, DebugHandle_repr_impl, HPy_tp_repr) +static UHPy DebugHandle_repr_impl(HPyContext uctx, UHPy self) +{ + DebugHandleObject *dh = HPy_CAST(uctx, DebugHandleObject, self); + UHPy uh_fmt = HPy_NULL; + UHPy uh_id = HPy_NULL; + UHPy uh_args = HPy_NULL; + UHPy uh_result = HPy_NULL; + + uh_fmt = HPyUnicode_FromString(uctx, ""); + if (HPy_IsNull(uh_fmt)) + goto exit; + + uh_id = HPyLong_FromSsize_t(uctx, (HPy_ssize_t)dh->handle); + if (HPy_IsNull(uh_id)) + goto exit; + + uh_args = HPyTuple_FromArray(uctx, (UHPy[]){uh_id, dh->handle->uh}, 2); + if (HPy_IsNull(uh_args)) + goto exit; + + uh_result = HPy_Remainder(uctx, uh_fmt, uh_args); + + exit: + HPy_Close(uctx, uh_fmt); + HPy_Close(uctx, uh_id); + HPy_Close(uctx, uh_args); + return uh_result; +} + + + +static HPyDef *DebugHandleType_defs[] = { + &DebugHandle_obj, + &DebugHandle_id, + &DebugHandle_cmp, + &DebugHandle_repr, + NULL +}; + +static HPyType_Spec DebugHandleType_spec = { + .name = "hpy.debug._debug.DebugHandle", + .basicsize = sizeof(DebugHandleObject), + .flags = HPy_TPFLAGS_DEFAULT, + .defines = DebugHandleType_defs, +}; + + +static UHPy new_DebugHandleObj(HPyContext uctx, UHPy u_DebugHandleType, + DebugHandle *handle) +{ + DebugHandleObject *dhobj; + UHPy u_result = HPy_New(uctx, u_DebugHandleType, &dhobj); + dhobj->handle = handle; + return u_result; +} + + +/* ~~~~~~ definition of the module hpy.debug._debug ~~~~~~~ */ + +static HPyDef *module_defines[] = { + &new_generation, + &get_open_handles, + NULL +}; + +static HPyModuleDef moduledef = { + HPyModuleDef_HEAD_INIT, + .m_name = "hpy.debug._debug", + .m_doc = "HPy debug mode", + .m_size = -1, + .defines = module_defines +}; + + +HPy_MODINIT(_debug) +static UHPy init__debug_impl(HPyContext uctx) +{ + UHPy m = HPyModule_Create(uctx, &moduledef); + if (HPy_IsNull(m)) + return HPy_NULL; + + UHPy h_DebugHandleType = HPyType_FromSpec(uctx, &DebugHandleType_spec, NULL); + if (HPy_IsNull(h_DebugHandleType)) + return HPy_NULL; + HPy_SetAttr_s(uctx, m, "DebugHandle", h_DebugHandleType); + HPy_Close(uctx, h_DebugHandleType); + return m; +} diff --git a/hpy/debug/src/autogen_debug_ctx_call.i b/hpy/debug/src/autogen_debug_ctx_call.i new file mode 100644 index 000000000..fc93264f9 --- /dev/null +++ b/hpy/debug/src/autogen_debug_ctx_call.i @@ -0,0 +1,272 @@ + +/* + DO NOT EDIT THIS FILE! + + This file is automatically generated by hpy.tools.autogen.debug.autogen_debug_ctx_call_i + See also hpy.tools.autogen and hpy/tools/public_api.h + + Run this to regenerate: + make autogen + +*/ + + case HPyFunc_UNARYFUNC: { + HPyFunc_unaryfunc f = (HPyFunc_unaryfunc)func; + _HPyFunc_args_UNARYFUNC *a = (_HPyFunc_args_UNARYFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_BINARYFUNC: { + HPyFunc_binaryfunc f = (HPyFunc_binaryfunc)func; + _HPyFunc_args_BINARYFUNC *a = (_HPyFunc_args_BINARYFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_result = f(dctx, dh_arg0, dh_arg1); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_TERNARYFUNC: { + HPyFunc_ternaryfunc f = (HPyFunc_ternaryfunc)func; + _HPyFunc_args_TERNARYFUNC *a = (_HPyFunc_args_TERNARYFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + DHPy dh_result = f(dctx, dh_arg0, dh_arg1, dh_arg2); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_arg2); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_INQUIRY: { + HPyFunc_inquiry f = (HPyFunc_inquiry)func; + _HPyFunc_args_INQUIRY *a = (_HPyFunc_args_INQUIRY*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + a->result = f(dctx, dh_arg0); + DHPy_close(dctx, dh_arg0); + return; + } + case HPyFunc_LENFUNC: { + HPyFunc_lenfunc f = (HPyFunc_lenfunc)func; + _HPyFunc_args_LENFUNC *a = (_HPyFunc_args_LENFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + a->result = f(dctx, dh_arg0); + DHPy_close(dctx, dh_arg0); + return; + } + case HPyFunc_SSIZEARGFUNC: { + HPyFunc_ssizeargfunc f = (HPyFunc_ssizeargfunc)func; + _HPyFunc_args_SSIZEARGFUNC *a = (_HPyFunc_args_SSIZEARGFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0, a->arg1); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_SSIZESSIZEARGFUNC: { + HPyFunc_ssizessizeargfunc f = (HPyFunc_ssizessizeargfunc)func; + _HPyFunc_args_SSIZESSIZEARGFUNC *a = (_HPyFunc_args_SSIZESSIZEARGFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0, a->arg1, a->arg2); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_SSIZEOBJARGPROC: { + HPyFunc_ssizeobjargproc f = (HPyFunc_ssizeobjargproc)func; + _HPyFunc_args_SSIZEOBJARGPROC *a = (_HPyFunc_args_SSIZEOBJARGPROC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + a->result = f(dctx, dh_arg0, a->arg1, dh_arg2); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg2); + return; + } + case HPyFunc_SSIZESSIZEOBJARGPROC: { + HPyFunc_ssizessizeobjargproc f = (HPyFunc_ssizessizeobjargproc)func; + _HPyFunc_args_SSIZESSIZEOBJARGPROC *a = (_HPyFunc_args_SSIZESSIZEOBJARGPROC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg3 = _py2dh(dctx, a->arg3); + a->result = f(dctx, dh_arg0, a->arg1, a->arg2, dh_arg3); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg3); + return; + } + case HPyFunc_OBJOBJARGPROC: { + HPyFunc_objobjargproc f = (HPyFunc_objobjargproc)func; + _HPyFunc_args_OBJOBJARGPROC *a = (_HPyFunc_args_OBJOBJARGPROC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + a->result = f(dctx, dh_arg0, dh_arg1, dh_arg2); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_arg2); + return; + } + case HPyFunc_FREEFUNC: { + HPyFunc_freefunc f = (HPyFunc_freefunc)func; + _HPyFunc_args_FREEFUNC *a = (_HPyFunc_args_FREEFUNC*)args; + f(dctx, a->arg0); + return; + } + case HPyFunc_GETATTRFUNC: { + HPyFunc_getattrfunc f = (HPyFunc_getattrfunc)func; + _HPyFunc_args_GETATTRFUNC *a = (_HPyFunc_args_GETATTRFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0, a->arg1); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_GETATTROFUNC: { + HPyFunc_getattrofunc f = (HPyFunc_getattrofunc)func; + _HPyFunc_args_GETATTROFUNC *a = (_HPyFunc_args_GETATTROFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_result = f(dctx, dh_arg0, dh_arg1); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_SETATTRFUNC: { + HPyFunc_setattrfunc f = (HPyFunc_setattrfunc)func; + _HPyFunc_args_SETATTRFUNC *a = (_HPyFunc_args_SETATTRFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + a->result = f(dctx, dh_arg0, a->arg1, dh_arg2); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg2); + return; + } + case HPyFunc_SETATTROFUNC: { + HPyFunc_setattrofunc f = (HPyFunc_setattrofunc)func; + _HPyFunc_args_SETATTROFUNC *a = (_HPyFunc_args_SETATTROFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + a->result = f(dctx, dh_arg0, dh_arg1, dh_arg2); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_arg2); + return; + } + case HPyFunc_REPRFUNC: { + HPyFunc_reprfunc f = (HPyFunc_reprfunc)func; + _HPyFunc_args_REPRFUNC *a = (_HPyFunc_args_REPRFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_HASHFUNC: { + HPyFunc_hashfunc f = (HPyFunc_hashfunc)func; + _HPyFunc_args_HASHFUNC *a = (_HPyFunc_args_HASHFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + a->result = f(dctx, dh_arg0); + DHPy_close(dctx, dh_arg0); + return; + } + case HPyFunc_RICHCMPFUNC: { + HPyFunc_richcmpfunc f = (HPyFunc_richcmpfunc)func; + _HPyFunc_args_RICHCMPFUNC *a = (_HPyFunc_args_RICHCMPFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_result = f(dctx, dh_arg0, dh_arg1, a->arg2); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_GETITERFUNC: { + HPyFunc_getiterfunc f = (HPyFunc_getiterfunc)func; + _HPyFunc_args_GETITERFUNC *a = (_HPyFunc_args_GETITERFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_ITERNEXTFUNC: { + HPyFunc_iternextfunc f = (HPyFunc_iternextfunc)func; + _HPyFunc_args_ITERNEXTFUNC *a = (_HPyFunc_args_ITERNEXTFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_DESCRGETFUNC: { + HPyFunc_descrgetfunc f = (HPyFunc_descrgetfunc)func; + _HPyFunc_args_DESCRGETFUNC *a = (_HPyFunc_args_DESCRGETFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + DHPy dh_result = f(dctx, dh_arg0, dh_arg1, dh_arg2); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_arg2); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_DESCRSETFUNC: { + HPyFunc_descrsetfunc f = (HPyFunc_descrsetfunc)func; + _HPyFunc_args_DESCRSETFUNC *a = (_HPyFunc_args_DESCRSETFUNC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + DHPy dh_arg2 = _py2dh(dctx, a->arg2); + a->result = f(dctx, dh_arg0, dh_arg1, dh_arg2); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + DHPy_close(dctx, dh_arg2); + return; + } + case HPyFunc_GETTER: { + HPyFunc_getter f = (HPyFunc_getter)func; + _HPyFunc_args_GETTER *a = (_HPyFunc_args_GETTER*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_result = f(dctx, dh_arg0, a->arg1); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_SETTER: { + HPyFunc_setter f = (HPyFunc_setter)func; + _HPyFunc_args_SETTER *a = (_HPyFunc_args_SETTER*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + a->result = f(dctx, dh_arg0, dh_arg1, a->arg2); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + return; + } + case HPyFunc_OBJOBJPROC: { + HPyFunc_objobjproc f = (HPyFunc_objobjproc)func; + _HPyFunc_args_OBJOBJPROC *a = (_HPyFunc_args_OBJOBJPROC*)args; + DHPy dh_arg0 = _py2dh(dctx, a->arg0); + DHPy dh_arg1 = _py2dh(dctx, a->arg1); + a->result = f(dctx, dh_arg0, dh_arg1); + DHPy_close(dctx, dh_arg0); + DHPy_close(dctx, dh_arg1); + return; + } diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h new file mode 100644 index 000000000..2506e26a4 --- /dev/null +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -0,0 +1,341 @@ + +/* + DO NOT EDIT THIS FILE! + + This file is automatically generated by hpy.tools.autogen.debug.autogen_debug_ctx_init_h + See also hpy.tools.autogen and hpy/tools/public_api.h + + Run this to regenerate: + make autogen + +*/ + +DHPy debug_ctx_Module_Create(HPyContext dctx, HPyModuleDef *def); +DHPy debug_ctx_Dup(HPyContext dctx, DHPy h); +void debug_ctx_Close(HPyContext dctx, DHPy h); +DHPy debug_ctx_Long_FromLong(HPyContext dctx, long value); +DHPy debug_ctx_Long_FromUnsignedLong(HPyContext dctx, unsigned long value); +DHPy debug_ctx_Long_FromLongLong(HPyContext dctx, long long v); +DHPy debug_ctx_Long_FromUnsignedLongLong(HPyContext dctx, unsigned long long v); +DHPy debug_ctx_Long_FromSize_t(HPyContext dctx, size_t value); +DHPy debug_ctx_Long_FromSsize_t(HPyContext dctx, HPy_ssize_t value); +long debug_ctx_Long_AsLong(HPyContext dctx, DHPy h); +unsigned long debug_ctx_Long_AsUnsignedLong(HPyContext dctx, DHPy h); +unsigned long debug_ctx_Long_AsUnsignedLongMask(HPyContext dctx, DHPy h); +long long debug_ctx_Long_AsLongLong(HPyContext dctx, DHPy h); +unsigned long long debug_ctx_Long_AsUnsignedLongLong(HPyContext dctx, DHPy h); +unsigned long long debug_ctx_Long_AsUnsignedLongLongMask(HPyContext dctx, DHPy h); +size_t debug_ctx_Long_AsSize_t(HPyContext dctx, DHPy h); +HPy_ssize_t debug_ctx_Long_AsSsize_t(HPyContext dctx, DHPy h); +DHPy debug_ctx_Float_FromDouble(HPyContext dctx, double v); +double debug_ctx_Float_AsDouble(HPyContext dctx, DHPy h); +DHPy debug_ctx_Bool_FromLong(HPyContext dctx, long v); +HPy_ssize_t debug_ctx_Length(HPyContext dctx, DHPy h); +int debug_ctx_Number_Check(HPyContext dctx, DHPy h); +DHPy debug_ctx_Add(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Subtract(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Multiply(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_MatrixMultiply(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_FloorDivide(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_TrueDivide(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Remainder(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Divmod(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Power(HPyContext dctx, DHPy h1, DHPy h2, DHPy h3); +DHPy debug_ctx_Negative(HPyContext dctx, DHPy h1); +DHPy debug_ctx_Positive(HPyContext dctx, DHPy h1); +DHPy debug_ctx_Absolute(HPyContext dctx, DHPy h1); +DHPy debug_ctx_Invert(HPyContext dctx, DHPy h1); +DHPy debug_ctx_Lshift(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Rshift(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_And(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Xor(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Or(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_Index(HPyContext dctx, DHPy h1); +DHPy debug_ctx_Long(HPyContext dctx, DHPy h1); +DHPy debug_ctx_Float(HPyContext dctx, DHPy h1); +DHPy debug_ctx_InPlaceAdd(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceSubtract(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceMultiply(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceMatrixMultiply(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceFloorDivide(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceTrueDivide(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceRemainder(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlacePower(HPyContext dctx, DHPy h1, DHPy h2, DHPy h3); +DHPy debug_ctx_InPlaceLshift(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceRshift(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceAnd(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceXor(HPyContext dctx, DHPy h1, DHPy h2); +DHPy debug_ctx_InPlaceOr(HPyContext dctx, DHPy h1, DHPy h2); +int debug_ctx_Callable_Check(HPyContext dctx, DHPy h); +DHPy debug_ctx_CallTupleDict(HPyContext dctx, DHPy callable, DHPy args, DHPy kw); +void debug_ctx_FatalError(HPyContext dctx, const char *message); +void debug_ctx_Err_SetString(HPyContext dctx, DHPy h_type, const char *message); +void debug_ctx_Err_SetObject(HPyContext dctx, DHPy h_type, DHPy h_value); +int debug_ctx_Err_Occurred(HPyContext dctx); +DHPy debug_ctx_Err_NoMemory(HPyContext dctx); +void debug_ctx_Err_Clear(HPyContext dctx); +int debug_ctx_IsTrue(HPyContext dctx, DHPy h); +DHPy debug_ctx_Type_FromSpec(HPyContext dctx, HPyType_Spec *spec, HPyType_SpecParam *params); +DHPy debug_ctx_Type_GenericNew(HPyContext dctx, DHPy type, DHPy *args, HPy_ssize_t nargs, DHPy kw); +DHPy debug_ctx_GetAttr(HPyContext dctx, DHPy obj, DHPy name); +DHPy debug_ctx_GetAttr_s(HPyContext dctx, DHPy obj, const char *name); +int debug_ctx_HasAttr(HPyContext dctx, DHPy obj, DHPy name); +int debug_ctx_HasAttr_s(HPyContext dctx, DHPy obj, const char *name); +int debug_ctx_SetAttr(HPyContext dctx, DHPy obj, DHPy name, DHPy value); +int debug_ctx_SetAttr_s(HPyContext dctx, DHPy obj, const char *name, DHPy value); +DHPy debug_ctx_GetItem(HPyContext dctx, DHPy obj, DHPy key); +DHPy debug_ctx_GetItem_i(HPyContext dctx, DHPy obj, HPy_ssize_t idx); +DHPy debug_ctx_GetItem_s(HPyContext dctx, DHPy obj, const char *key); +int debug_ctx_SetItem(HPyContext dctx, DHPy obj, DHPy key, DHPy value); +int debug_ctx_SetItem_i(HPyContext dctx, DHPy obj, HPy_ssize_t idx, DHPy value); +int debug_ctx_SetItem_s(HPyContext dctx, DHPy obj, const char *key, DHPy value); +DHPy debug_ctx_Type(HPyContext dctx, DHPy obj); +int debug_ctx_TypeCheck(HPyContext dctx, DHPy obj, DHPy type); +void *debug_ctx_Cast(HPyContext dctx, DHPy h); +DHPy debug_ctx_New(HPyContext dctx, DHPy h_type, void **data); +DHPy debug_ctx_Repr(HPyContext dctx, DHPy obj); +DHPy debug_ctx_Str(HPyContext dctx, DHPy obj); +DHPy debug_ctx_ASCII(HPyContext dctx, DHPy obj); +DHPy debug_ctx_Bytes(HPyContext dctx, DHPy obj); +DHPy debug_ctx_RichCompare(HPyContext dctx, DHPy v, DHPy w, int op); +int debug_ctx_RichCompareBool(HPyContext dctx, DHPy v, DHPy w, int op); +HPy_hash_t debug_ctx_Hash(HPyContext dctx, DHPy obj); +int debug_ctx_Bytes_Check(HPyContext dctx, DHPy h); +HPy_ssize_t debug_ctx_Bytes_Size(HPyContext dctx, DHPy h); +HPy_ssize_t debug_ctx_Bytes_GET_SIZE(HPyContext dctx, DHPy h); +char *debug_ctx_Bytes_AsString(HPyContext dctx, DHPy h); +char *debug_ctx_Bytes_AS_STRING(HPyContext dctx, DHPy h); +DHPy debug_ctx_Bytes_FromString(HPyContext dctx, const char *v); +DHPy debug_ctx_Bytes_FromStringAndSize(HPyContext dctx, const char *v, HPy_ssize_t len); +DHPy debug_ctx_Unicode_FromString(HPyContext dctx, const char *utf8); +int debug_ctx_Unicode_Check(HPyContext dctx, DHPy h); +DHPy debug_ctx_Unicode_AsUTF8String(HPyContext dctx, DHPy h); +DHPy debug_ctx_Unicode_FromWideChar(HPyContext dctx, const wchar_t *w, HPy_ssize_t size); +int debug_ctx_List_Check(HPyContext dctx, DHPy h); +DHPy debug_ctx_List_New(HPyContext dctx, HPy_ssize_t len); +int debug_ctx_List_Append(HPyContext dctx, DHPy h_list, DHPy h_item); +int debug_ctx_Dict_Check(HPyContext dctx, DHPy h); +DHPy debug_ctx_Dict_New(HPyContext dctx); +int debug_ctx_Tuple_Check(HPyContext dctx, DHPy h); +DHPy debug_ctx_Tuple_FromArray(HPyContext dctx, DHPy items[], HPy_ssize_t n); +DHPy debug_ctx_FromPyObject(HPyContext dctx, cpy_PyObject *obj); +cpy_PyObject *debug_ctx_AsPyObject(HPyContext dctx, DHPy h); +void debug_ctx_CallRealFunctionFromTrampoline(HPyContext dctx, HPyFunc_Signature sig, void *func, void *args); +void debug_ctx_CallDestroyAndThenDealloc(HPyContext dctx, void *func, cpy_PyObject *self); +HPyListBuilder debug_ctx_ListBuilder_New(HPyContext dctx, HPy_ssize_t initial_size); +void debug_ctx_ListBuilder_Set(HPyContext dctx, HPyListBuilder builder, HPy_ssize_t index, DHPy h_item); +DHPy debug_ctx_ListBuilder_Build(HPyContext dctx, HPyListBuilder builder); +void debug_ctx_ListBuilder_Cancel(HPyContext dctx, HPyListBuilder builder); +HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext dctx, HPy_ssize_t initial_size); +void debug_ctx_TupleBuilder_Set(HPyContext dctx, HPyTupleBuilder builder, HPy_ssize_t index, DHPy h_item); +DHPy debug_ctx_TupleBuilder_Build(HPyContext dctx, HPyTupleBuilder builder); +void debug_ctx_TupleBuilder_Cancel(HPyContext dctx, HPyTupleBuilder builder); +HPyTracker debug_ctx_Tracker_New(HPyContext dctx, HPy_ssize_t size); +int debug_ctx_Tracker_Add(HPyContext dctx, HPyTracker ht, DHPy h); +void debug_ctx_Tracker_ForgetAll(HPyContext dctx, HPyTracker ht); +void debug_ctx_Tracker_Close(HPyContext dctx, HPyTracker ht); +void debug_ctx_Dump(HPyContext dctx, DHPy h); + +static inline void debug_ctx_init_fields(HPyContext dctx, HPyContext uctx) +{ + dctx->h_None = DHPy_wrap(dctx, uctx->h_None); + dctx->h_True = DHPy_wrap(dctx, uctx->h_True); + dctx->h_False = DHPy_wrap(dctx, uctx->h_False); + dctx->h_NotImplemented = DHPy_wrap(dctx, uctx->h_NotImplemented); + dctx->h_Ellipsis = DHPy_wrap(dctx, uctx->h_Ellipsis); + dctx->h_BaseException = DHPy_wrap(dctx, uctx->h_BaseException); + dctx->h_Exception = DHPy_wrap(dctx, uctx->h_Exception); + dctx->h_StopAsyncIteration = DHPy_wrap(dctx, uctx->h_StopAsyncIteration); + dctx->h_StopIteration = DHPy_wrap(dctx, uctx->h_StopIteration); + dctx->h_GeneratorExit = DHPy_wrap(dctx, uctx->h_GeneratorExit); + dctx->h_ArithmeticError = DHPy_wrap(dctx, uctx->h_ArithmeticError); + dctx->h_LookupError = DHPy_wrap(dctx, uctx->h_LookupError); + dctx->h_AssertionError = DHPy_wrap(dctx, uctx->h_AssertionError); + dctx->h_AttributeError = DHPy_wrap(dctx, uctx->h_AttributeError); + dctx->h_BufferError = DHPy_wrap(dctx, uctx->h_BufferError); + dctx->h_EOFError = DHPy_wrap(dctx, uctx->h_EOFError); + dctx->h_FloatingPointError = DHPy_wrap(dctx, uctx->h_FloatingPointError); + dctx->h_OSError = DHPy_wrap(dctx, uctx->h_OSError); + dctx->h_ImportError = DHPy_wrap(dctx, uctx->h_ImportError); + dctx->h_ModuleNotFoundError = DHPy_wrap(dctx, uctx->h_ModuleNotFoundError); + dctx->h_IndexError = DHPy_wrap(dctx, uctx->h_IndexError); + dctx->h_KeyError = DHPy_wrap(dctx, uctx->h_KeyError); + dctx->h_KeyboardInterrupt = DHPy_wrap(dctx, uctx->h_KeyboardInterrupt); + dctx->h_MemoryError = DHPy_wrap(dctx, uctx->h_MemoryError); + dctx->h_NameError = DHPy_wrap(dctx, uctx->h_NameError); + dctx->h_OverflowError = DHPy_wrap(dctx, uctx->h_OverflowError); + dctx->h_RuntimeError = DHPy_wrap(dctx, uctx->h_RuntimeError); + dctx->h_RecursionError = DHPy_wrap(dctx, uctx->h_RecursionError); + dctx->h_NotImplementedError = DHPy_wrap(dctx, uctx->h_NotImplementedError); + dctx->h_SyntaxError = DHPy_wrap(dctx, uctx->h_SyntaxError); + dctx->h_IndentationError = DHPy_wrap(dctx, uctx->h_IndentationError); + dctx->h_TabError = DHPy_wrap(dctx, uctx->h_TabError); + dctx->h_ReferenceError = DHPy_wrap(dctx, uctx->h_ReferenceError); + dctx->h_SystemError = DHPy_wrap(dctx, uctx->h_SystemError); + dctx->h_SystemExit = DHPy_wrap(dctx, uctx->h_SystemExit); + dctx->h_TypeError = DHPy_wrap(dctx, uctx->h_TypeError); + dctx->h_UnboundLocalError = DHPy_wrap(dctx, uctx->h_UnboundLocalError); + dctx->h_UnicodeError = DHPy_wrap(dctx, uctx->h_UnicodeError); + dctx->h_UnicodeEncodeError = DHPy_wrap(dctx, uctx->h_UnicodeEncodeError); + dctx->h_UnicodeDecodeError = DHPy_wrap(dctx, uctx->h_UnicodeDecodeError); + dctx->h_UnicodeTranslateError = DHPy_wrap(dctx, uctx->h_UnicodeTranslateError); + dctx->h_ValueError = DHPy_wrap(dctx, uctx->h_ValueError); + dctx->h_ZeroDivisionError = DHPy_wrap(dctx, uctx->h_ZeroDivisionError); + dctx->h_BlockingIOError = DHPy_wrap(dctx, uctx->h_BlockingIOError); + dctx->h_BrokenPipeError = DHPy_wrap(dctx, uctx->h_BrokenPipeError); + dctx->h_ChildProcessError = DHPy_wrap(dctx, uctx->h_ChildProcessError); + dctx->h_ConnectionError = DHPy_wrap(dctx, uctx->h_ConnectionError); + dctx->h_ConnectionAbortedError = DHPy_wrap(dctx, uctx->h_ConnectionAbortedError); + dctx->h_ConnectionRefusedError = DHPy_wrap(dctx, uctx->h_ConnectionRefusedError); + dctx->h_ConnectionResetError = DHPy_wrap(dctx, uctx->h_ConnectionResetError); + dctx->h_FileExistsError = DHPy_wrap(dctx, uctx->h_FileExistsError); + dctx->h_FileNotFoundError = DHPy_wrap(dctx, uctx->h_FileNotFoundError); + dctx->h_InterruptedError = DHPy_wrap(dctx, uctx->h_InterruptedError); + dctx->h_IsADirectoryError = DHPy_wrap(dctx, uctx->h_IsADirectoryError); + dctx->h_NotADirectoryError = DHPy_wrap(dctx, uctx->h_NotADirectoryError); + dctx->h_PermissionError = DHPy_wrap(dctx, uctx->h_PermissionError); + dctx->h_ProcessLookupError = DHPy_wrap(dctx, uctx->h_ProcessLookupError); + dctx->h_TimeoutError = DHPy_wrap(dctx, uctx->h_TimeoutError); + dctx->h_Warning = DHPy_wrap(dctx, uctx->h_Warning); + dctx->h_UserWarning = DHPy_wrap(dctx, uctx->h_UserWarning); + dctx->h_DeprecationWarning = DHPy_wrap(dctx, uctx->h_DeprecationWarning); + dctx->h_PendingDeprecationWarning = DHPy_wrap(dctx, uctx->h_PendingDeprecationWarning); + dctx->h_SyntaxWarning = DHPy_wrap(dctx, uctx->h_SyntaxWarning); + dctx->h_RuntimeWarning = DHPy_wrap(dctx, uctx->h_RuntimeWarning); + dctx->h_FutureWarning = DHPy_wrap(dctx, uctx->h_FutureWarning); + dctx->h_ImportWarning = DHPy_wrap(dctx, uctx->h_ImportWarning); + dctx->h_UnicodeWarning = DHPy_wrap(dctx, uctx->h_UnicodeWarning); + dctx->h_BytesWarning = DHPy_wrap(dctx, uctx->h_BytesWarning); + dctx->h_ResourceWarning = DHPy_wrap(dctx, uctx->h_ResourceWarning); + dctx->h_BaseObjectType = DHPy_wrap(dctx, uctx->h_BaseObjectType); + dctx->h_TypeType = DHPy_wrap(dctx, uctx->h_TypeType); + dctx->h_LongType = DHPy_wrap(dctx, uctx->h_LongType); + dctx->h_UnicodeType = DHPy_wrap(dctx, uctx->h_UnicodeType); + dctx->h_TupleType = DHPy_wrap(dctx, uctx->h_TupleType); + dctx->h_ListType = DHPy_wrap(dctx, uctx->h_ListType); + dctx->ctx_Module_Create = &debug_ctx_Module_Create; + dctx->ctx_Dup = &debug_ctx_Dup; + dctx->ctx_Close = &debug_ctx_Close; + dctx->ctx_Long_FromLong = &debug_ctx_Long_FromLong; + dctx->ctx_Long_FromUnsignedLong = &debug_ctx_Long_FromUnsignedLong; + dctx->ctx_Long_FromLongLong = &debug_ctx_Long_FromLongLong; + dctx->ctx_Long_FromUnsignedLongLong = &debug_ctx_Long_FromUnsignedLongLong; + dctx->ctx_Long_FromSize_t = &debug_ctx_Long_FromSize_t; + dctx->ctx_Long_FromSsize_t = &debug_ctx_Long_FromSsize_t; + dctx->ctx_Long_AsLong = &debug_ctx_Long_AsLong; + dctx->ctx_Long_AsUnsignedLong = &debug_ctx_Long_AsUnsignedLong; + dctx->ctx_Long_AsUnsignedLongMask = &debug_ctx_Long_AsUnsignedLongMask; + dctx->ctx_Long_AsLongLong = &debug_ctx_Long_AsLongLong; + dctx->ctx_Long_AsUnsignedLongLong = &debug_ctx_Long_AsUnsignedLongLong; + dctx->ctx_Long_AsUnsignedLongLongMask = &debug_ctx_Long_AsUnsignedLongLongMask; + dctx->ctx_Long_AsSize_t = &debug_ctx_Long_AsSize_t; + dctx->ctx_Long_AsSsize_t = &debug_ctx_Long_AsSsize_t; + dctx->ctx_Float_FromDouble = &debug_ctx_Float_FromDouble; + dctx->ctx_Float_AsDouble = &debug_ctx_Float_AsDouble; + dctx->ctx_Bool_FromLong = &debug_ctx_Bool_FromLong; + dctx->ctx_Length = &debug_ctx_Length; + dctx->ctx_Number_Check = &debug_ctx_Number_Check; + dctx->ctx_Add = &debug_ctx_Add; + dctx->ctx_Subtract = &debug_ctx_Subtract; + dctx->ctx_Multiply = &debug_ctx_Multiply; + dctx->ctx_MatrixMultiply = &debug_ctx_MatrixMultiply; + dctx->ctx_FloorDivide = &debug_ctx_FloorDivide; + dctx->ctx_TrueDivide = &debug_ctx_TrueDivide; + dctx->ctx_Remainder = &debug_ctx_Remainder; + dctx->ctx_Divmod = &debug_ctx_Divmod; + dctx->ctx_Power = &debug_ctx_Power; + dctx->ctx_Negative = &debug_ctx_Negative; + dctx->ctx_Positive = &debug_ctx_Positive; + dctx->ctx_Absolute = &debug_ctx_Absolute; + dctx->ctx_Invert = &debug_ctx_Invert; + dctx->ctx_Lshift = &debug_ctx_Lshift; + dctx->ctx_Rshift = &debug_ctx_Rshift; + dctx->ctx_And = &debug_ctx_And; + dctx->ctx_Xor = &debug_ctx_Xor; + dctx->ctx_Or = &debug_ctx_Or; + dctx->ctx_Index = &debug_ctx_Index; + dctx->ctx_Long = &debug_ctx_Long; + dctx->ctx_Float = &debug_ctx_Float; + dctx->ctx_InPlaceAdd = &debug_ctx_InPlaceAdd; + dctx->ctx_InPlaceSubtract = &debug_ctx_InPlaceSubtract; + dctx->ctx_InPlaceMultiply = &debug_ctx_InPlaceMultiply; + dctx->ctx_InPlaceMatrixMultiply = &debug_ctx_InPlaceMatrixMultiply; + dctx->ctx_InPlaceFloorDivide = &debug_ctx_InPlaceFloorDivide; + dctx->ctx_InPlaceTrueDivide = &debug_ctx_InPlaceTrueDivide; + dctx->ctx_InPlaceRemainder = &debug_ctx_InPlaceRemainder; + dctx->ctx_InPlacePower = &debug_ctx_InPlacePower; + dctx->ctx_InPlaceLshift = &debug_ctx_InPlaceLshift; + dctx->ctx_InPlaceRshift = &debug_ctx_InPlaceRshift; + dctx->ctx_InPlaceAnd = &debug_ctx_InPlaceAnd; + dctx->ctx_InPlaceXor = &debug_ctx_InPlaceXor; + dctx->ctx_InPlaceOr = &debug_ctx_InPlaceOr; + dctx->ctx_Callable_Check = &debug_ctx_Callable_Check; + dctx->ctx_CallTupleDict = &debug_ctx_CallTupleDict; + dctx->ctx_FatalError = &debug_ctx_FatalError; + dctx->ctx_Err_SetString = &debug_ctx_Err_SetString; + dctx->ctx_Err_SetObject = &debug_ctx_Err_SetObject; + dctx->ctx_Err_Occurred = &debug_ctx_Err_Occurred; + dctx->ctx_Err_NoMemory = &debug_ctx_Err_NoMemory; + dctx->ctx_Err_Clear = &debug_ctx_Err_Clear; + dctx->ctx_IsTrue = &debug_ctx_IsTrue; + dctx->ctx_Type_FromSpec = &debug_ctx_Type_FromSpec; + dctx->ctx_Type_GenericNew = &debug_ctx_Type_GenericNew; + dctx->ctx_GetAttr = &debug_ctx_GetAttr; + dctx->ctx_GetAttr_s = &debug_ctx_GetAttr_s; + dctx->ctx_HasAttr = &debug_ctx_HasAttr; + dctx->ctx_HasAttr_s = &debug_ctx_HasAttr_s; + dctx->ctx_SetAttr = &debug_ctx_SetAttr; + dctx->ctx_SetAttr_s = &debug_ctx_SetAttr_s; + dctx->ctx_GetItem = &debug_ctx_GetItem; + dctx->ctx_GetItem_i = &debug_ctx_GetItem_i; + dctx->ctx_GetItem_s = &debug_ctx_GetItem_s; + dctx->ctx_SetItem = &debug_ctx_SetItem; + dctx->ctx_SetItem_i = &debug_ctx_SetItem_i; + dctx->ctx_SetItem_s = &debug_ctx_SetItem_s; + dctx->ctx_Type = &debug_ctx_Type; + dctx->ctx_TypeCheck = &debug_ctx_TypeCheck; + dctx->ctx_Cast = &debug_ctx_Cast; + dctx->ctx_New = &debug_ctx_New; + dctx->ctx_Repr = &debug_ctx_Repr; + dctx->ctx_Str = &debug_ctx_Str; + dctx->ctx_ASCII = &debug_ctx_ASCII; + dctx->ctx_Bytes = &debug_ctx_Bytes; + dctx->ctx_RichCompare = &debug_ctx_RichCompare; + dctx->ctx_RichCompareBool = &debug_ctx_RichCompareBool; + dctx->ctx_Hash = &debug_ctx_Hash; + dctx->ctx_Bytes_Check = &debug_ctx_Bytes_Check; + dctx->ctx_Bytes_Size = &debug_ctx_Bytes_Size; + dctx->ctx_Bytes_GET_SIZE = &debug_ctx_Bytes_GET_SIZE; + dctx->ctx_Bytes_AsString = &debug_ctx_Bytes_AsString; + dctx->ctx_Bytes_AS_STRING = &debug_ctx_Bytes_AS_STRING; + dctx->ctx_Bytes_FromString = &debug_ctx_Bytes_FromString; + dctx->ctx_Bytes_FromStringAndSize = &debug_ctx_Bytes_FromStringAndSize; + dctx->ctx_Unicode_FromString = &debug_ctx_Unicode_FromString; + dctx->ctx_Unicode_Check = &debug_ctx_Unicode_Check; + dctx->ctx_Unicode_AsUTF8String = &debug_ctx_Unicode_AsUTF8String; + dctx->ctx_Unicode_FromWideChar = &debug_ctx_Unicode_FromWideChar; + dctx->ctx_List_Check = &debug_ctx_List_Check; + dctx->ctx_List_New = &debug_ctx_List_New; + dctx->ctx_List_Append = &debug_ctx_List_Append; + dctx->ctx_Dict_Check = &debug_ctx_Dict_Check; + dctx->ctx_Dict_New = &debug_ctx_Dict_New; + dctx->ctx_Tuple_Check = &debug_ctx_Tuple_Check; + dctx->ctx_Tuple_FromArray = &debug_ctx_Tuple_FromArray; + dctx->ctx_FromPyObject = &debug_ctx_FromPyObject; + dctx->ctx_AsPyObject = &debug_ctx_AsPyObject; + dctx->ctx_CallRealFunctionFromTrampoline = &debug_ctx_CallRealFunctionFromTrampoline; + dctx->ctx_CallDestroyAndThenDealloc = &debug_ctx_CallDestroyAndThenDealloc; + dctx->ctx_ListBuilder_New = &debug_ctx_ListBuilder_New; + dctx->ctx_ListBuilder_Set = &debug_ctx_ListBuilder_Set; + dctx->ctx_ListBuilder_Build = &debug_ctx_ListBuilder_Build; + dctx->ctx_ListBuilder_Cancel = &debug_ctx_ListBuilder_Cancel; + dctx->ctx_TupleBuilder_New = &debug_ctx_TupleBuilder_New; + dctx->ctx_TupleBuilder_Set = &debug_ctx_TupleBuilder_Set; + dctx->ctx_TupleBuilder_Build = &debug_ctx_TupleBuilder_Build; + dctx->ctx_TupleBuilder_Cancel = &debug_ctx_TupleBuilder_Cancel; + dctx->ctx_Tracker_New = &debug_ctx_Tracker_New; + dctx->ctx_Tracker_Add = &debug_ctx_Tracker_Add; + dctx->ctx_Tracker_ForgetAll = &debug_ctx_Tracker_ForgetAll; + dctx->ctx_Tracker_Close = &debug_ctx_Tracker_Close; + dctx->ctx_Dump = &debug_ctx_Dump; +} diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c new file mode 100644 index 000000000..c9f5937fc --- /dev/null +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -0,0 +1,614 @@ + +/* + DO NOT EDIT THIS FILE! + + This file is automatically generated by hpy.tools.autogen.debug.autogen_debug_wrappers + See also hpy.tools.autogen and hpy/tools/public_api.h + + Run this to regenerate: + make autogen + +*/ + +#include "debug_internal.h" + +DHPy debug_ctx_Module_Create(HPyContext dctx, HPyModuleDef *def) +{ + return DHPy_wrap(dctx, HPyModule_Create(get_info(dctx)->uctx, def)); +} + +DHPy debug_ctx_Dup(HPyContext dctx, DHPy h) +{ + return DHPy_wrap(dctx, HPy_Dup(get_info(dctx)->uctx, DHPy_unwrap(h))); +} + +DHPy debug_ctx_Long_FromLong(HPyContext dctx, long value) +{ + return DHPy_wrap(dctx, HPyLong_FromLong(get_info(dctx)->uctx, value)); +} + +DHPy debug_ctx_Long_FromUnsignedLong(HPyContext dctx, unsigned long value) +{ + return DHPy_wrap(dctx, HPyLong_FromUnsignedLong(get_info(dctx)->uctx, value)); +} + +DHPy debug_ctx_Long_FromLongLong(HPyContext dctx, long long v) +{ + return DHPy_wrap(dctx, HPyLong_FromLongLong(get_info(dctx)->uctx, v)); +} + +DHPy debug_ctx_Long_FromUnsignedLongLong(HPyContext dctx, unsigned long long v) +{ + return DHPy_wrap(dctx, HPyLong_FromUnsignedLongLong(get_info(dctx)->uctx, v)); +} + +DHPy debug_ctx_Long_FromSize_t(HPyContext dctx, size_t value) +{ + return DHPy_wrap(dctx, HPyLong_FromSize_t(get_info(dctx)->uctx, value)); +} + +DHPy debug_ctx_Long_FromSsize_t(HPyContext dctx, HPy_ssize_t value) +{ + return DHPy_wrap(dctx, HPyLong_FromSsize_t(get_info(dctx)->uctx, value)); +} + +long debug_ctx_Long_AsLong(HPyContext dctx, DHPy h) +{ + return HPyLong_AsLong(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +unsigned long debug_ctx_Long_AsUnsignedLong(HPyContext dctx, DHPy h) +{ + return HPyLong_AsUnsignedLong(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +unsigned long debug_ctx_Long_AsUnsignedLongMask(HPyContext dctx, DHPy h) +{ + return HPyLong_AsUnsignedLongMask(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +long long debug_ctx_Long_AsLongLong(HPyContext dctx, DHPy h) +{ + return HPyLong_AsLongLong(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +unsigned long long debug_ctx_Long_AsUnsignedLongLong(HPyContext dctx, DHPy h) +{ + return HPyLong_AsUnsignedLongLong(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +unsigned long long debug_ctx_Long_AsUnsignedLongLongMask(HPyContext dctx, DHPy h) +{ + return HPyLong_AsUnsignedLongLongMask(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +size_t debug_ctx_Long_AsSize_t(HPyContext dctx, DHPy h) +{ + return HPyLong_AsSize_t(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +HPy_ssize_t debug_ctx_Long_AsSsize_t(HPyContext dctx, DHPy h) +{ + return HPyLong_AsSsize_t(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_Float_FromDouble(HPyContext dctx, double v) +{ + return DHPy_wrap(dctx, HPyFloat_FromDouble(get_info(dctx)->uctx, v)); +} + +double debug_ctx_Float_AsDouble(HPyContext dctx, DHPy h) +{ + return HPyFloat_AsDouble(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_Bool_FromLong(HPyContext dctx, long v) +{ + return DHPy_wrap(dctx, HPyBool_FromLong(get_info(dctx)->uctx, v)); +} + +HPy_ssize_t debug_ctx_Length(HPyContext dctx, DHPy h) +{ + return HPy_Length(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +int debug_ctx_Number_Check(HPyContext dctx, DHPy h) +{ + return HPyNumber_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_Add(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Add(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Subtract(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Subtract(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Multiply(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Multiply(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_MatrixMultiply(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_MatrixMultiply(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_FloorDivide(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_FloorDivide(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_TrueDivide(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_TrueDivide(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Remainder(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Remainder(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Divmod(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Divmod(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Power(HPyContext dctx, DHPy h1, DHPy h2, DHPy h3) +{ + return DHPy_wrap(dctx, HPy_Power(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2), DHPy_unwrap(h3))); +} + +DHPy debug_ctx_Negative(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Negative(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_Positive(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Positive(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_Absolute(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Absolute(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_Invert(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Invert(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_Lshift(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Lshift(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Rshift(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Rshift(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_And(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_And(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Xor(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Xor(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Or(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_Or(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_Index(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Index(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_Long(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Long(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_Float(HPyContext dctx, DHPy h1) +{ + return DHPy_wrap(dctx, HPy_Float(get_info(dctx)->uctx, DHPy_unwrap(h1))); +} + +DHPy debug_ctx_InPlaceAdd(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceAdd(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceSubtract(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceSubtract(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceMultiply(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceMultiply(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceMatrixMultiply(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceMatrixMultiply(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceFloorDivide(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceFloorDivide(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceTrueDivide(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceTrueDivide(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceRemainder(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceRemainder(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlacePower(HPyContext dctx, DHPy h1, DHPy h2, DHPy h3) +{ + return DHPy_wrap(dctx, HPy_InPlacePower(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2), DHPy_unwrap(h3))); +} + +DHPy debug_ctx_InPlaceLshift(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceLshift(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceRshift(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceRshift(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceAnd(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceAnd(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceXor(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceXor(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +DHPy debug_ctx_InPlaceOr(HPyContext dctx, DHPy h1, DHPy h2) +{ + return DHPy_wrap(dctx, HPy_InPlaceOr(get_info(dctx)->uctx, DHPy_unwrap(h1), DHPy_unwrap(h2))); +} + +int debug_ctx_Callable_Check(HPyContext dctx, DHPy h) +{ + return HPyCallable_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_CallTupleDict(HPyContext dctx, DHPy callable, DHPy args, DHPy kw) +{ + return DHPy_wrap(dctx, HPy_CallTupleDict(get_info(dctx)->uctx, DHPy_unwrap(callable), DHPy_unwrap(args), DHPy_unwrap(kw))); +} + +void debug_ctx_FatalError(HPyContext dctx, const char *message) +{ + HPy_FatalError(get_info(dctx)->uctx, message); +} + +void debug_ctx_Err_SetString(HPyContext dctx, DHPy h_type, const char *message) +{ + HPyErr_SetString(get_info(dctx)->uctx, DHPy_unwrap(h_type), message); +} + +void debug_ctx_Err_SetObject(HPyContext dctx, DHPy h_type, DHPy h_value) +{ + HPyErr_SetObject(get_info(dctx)->uctx, DHPy_unwrap(h_type), DHPy_unwrap(h_value)); +} + +int debug_ctx_Err_Occurred(HPyContext dctx) +{ + return HPyErr_Occurred(get_info(dctx)->uctx); +} + +DHPy debug_ctx_Err_NoMemory(HPyContext dctx) +{ + return DHPy_wrap(dctx, HPyErr_NoMemory(get_info(dctx)->uctx)); +} + +void debug_ctx_Err_Clear(HPyContext dctx) +{ + HPyErr_Clear(get_info(dctx)->uctx); +} + +int debug_ctx_IsTrue(HPyContext dctx, DHPy h) +{ + return HPy_IsTrue(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_GetAttr(HPyContext dctx, DHPy obj, DHPy name) +{ + return DHPy_wrap(dctx, HPy_GetAttr(get_info(dctx)->uctx, DHPy_unwrap(obj), DHPy_unwrap(name))); +} + +DHPy debug_ctx_GetAttr_s(HPyContext dctx, DHPy obj, const char *name) +{ + return DHPy_wrap(dctx, HPy_GetAttr_s(get_info(dctx)->uctx, DHPy_unwrap(obj), name)); +} + +int debug_ctx_HasAttr(HPyContext dctx, DHPy obj, DHPy name) +{ + return HPy_HasAttr(get_info(dctx)->uctx, DHPy_unwrap(obj), DHPy_unwrap(name)); +} + +int debug_ctx_HasAttr_s(HPyContext dctx, DHPy obj, const char *name) +{ + return HPy_HasAttr_s(get_info(dctx)->uctx, DHPy_unwrap(obj), name); +} + +int debug_ctx_SetAttr(HPyContext dctx, DHPy obj, DHPy name, DHPy value) +{ + return HPy_SetAttr(get_info(dctx)->uctx, DHPy_unwrap(obj), DHPy_unwrap(name), DHPy_unwrap(value)); +} + +int debug_ctx_SetAttr_s(HPyContext dctx, DHPy obj, const char *name, DHPy value) +{ + return HPy_SetAttr_s(get_info(dctx)->uctx, DHPy_unwrap(obj), name, DHPy_unwrap(value)); +} + +DHPy debug_ctx_GetItem(HPyContext dctx, DHPy obj, DHPy key) +{ + return DHPy_wrap(dctx, HPy_GetItem(get_info(dctx)->uctx, DHPy_unwrap(obj), DHPy_unwrap(key))); +} + +DHPy debug_ctx_GetItem_i(HPyContext dctx, DHPy obj, HPy_ssize_t idx) +{ + return DHPy_wrap(dctx, HPy_GetItem_i(get_info(dctx)->uctx, DHPy_unwrap(obj), idx)); +} + +DHPy debug_ctx_GetItem_s(HPyContext dctx, DHPy obj, const char *key) +{ + return DHPy_wrap(dctx, HPy_GetItem_s(get_info(dctx)->uctx, DHPy_unwrap(obj), key)); +} + +int debug_ctx_SetItem(HPyContext dctx, DHPy obj, DHPy key, DHPy value) +{ + return HPy_SetItem(get_info(dctx)->uctx, DHPy_unwrap(obj), DHPy_unwrap(key), DHPy_unwrap(value)); +} + +int debug_ctx_SetItem_i(HPyContext dctx, DHPy obj, HPy_ssize_t idx, DHPy value) +{ + return HPy_SetItem_i(get_info(dctx)->uctx, DHPy_unwrap(obj), idx, DHPy_unwrap(value)); +} + +int debug_ctx_SetItem_s(HPyContext dctx, DHPy obj, const char *key, DHPy value) +{ + return HPy_SetItem_s(get_info(dctx)->uctx, DHPy_unwrap(obj), key, DHPy_unwrap(value)); +} + +DHPy debug_ctx_Type(HPyContext dctx, DHPy obj) +{ + return DHPy_wrap(dctx, HPy_Type(get_info(dctx)->uctx, DHPy_unwrap(obj))); +} + +int debug_ctx_TypeCheck(HPyContext dctx, DHPy obj, DHPy type) +{ + return HPy_TypeCheck(get_info(dctx)->uctx, DHPy_unwrap(obj), DHPy_unwrap(type)); +} + +void *debug_ctx_Cast(HPyContext dctx, DHPy h) +{ + return _HPy_Cast(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_New(HPyContext dctx, DHPy h_type, void **data) +{ + return DHPy_wrap(dctx, _HPy_New(get_info(dctx)->uctx, DHPy_unwrap(h_type), data)); +} + +DHPy debug_ctx_Repr(HPyContext dctx, DHPy obj) +{ + return DHPy_wrap(dctx, HPy_Repr(get_info(dctx)->uctx, DHPy_unwrap(obj))); +} + +DHPy debug_ctx_Str(HPyContext dctx, DHPy obj) +{ + return DHPy_wrap(dctx, HPy_Str(get_info(dctx)->uctx, DHPy_unwrap(obj))); +} + +DHPy debug_ctx_ASCII(HPyContext dctx, DHPy obj) +{ + return DHPy_wrap(dctx, HPy_ASCII(get_info(dctx)->uctx, DHPy_unwrap(obj))); +} + +DHPy debug_ctx_Bytes(HPyContext dctx, DHPy obj) +{ + return DHPy_wrap(dctx, HPy_Bytes(get_info(dctx)->uctx, DHPy_unwrap(obj))); +} + +DHPy debug_ctx_RichCompare(HPyContext dctx, DHPy v, DHPy w, int op) +{ + return DHPy_wrap(dctx, HPy_RichCompare(get_info(dctx)->uctx, DHPy_unwrap(v), DHPy_unwrap(w), op)); +} + +int debug_ctx_RichCompareBool(HPyContext dctx, DHPy v, DHPy w, int op) +{ + return HPy_RichCompareBool(get_info(dctx)->uctx, DHPy_unwrap(v), DHPy_unwrap(w), op); +} + +HPy_hash_t debug_ctx_Hash(HPyContext dctx, DHPy obj) +{ + return HPy_Hash(get_info(dctx)->uctx, DHPy_unwrap(obj)); +} + +int debug_ctx_Bytes_Check(HPyContext dctx, DHPy h) +{ + return HPyBytes_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +HPy_ssize_t debug_ctx_Bytes_Size(HPyContext dctx, DHPy h) +{ + return HPyBytes_Size(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +HPy_ssize_t debug_ctx_Bytes_GET_SIZE(HPyContext dctx, DHPy h) +{ + return HPyBytes_GET_SIZE(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +char *debug_ctx_Bytes_AsString(HPyContext dctx, DHPy h) +{ + return HPyBytes_AsString(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +char *debug_ctx_Bytes_AS_STRING(HPyContext dctx, DHPy h) +{ + return HPyBytes_AS_STRING(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_Bytes_FromString(HPyContext dctx, const char *v) +{ + return DHPy_wrap(dctx, HPyBytes_FromString(get_info(dctx)->uctx, v)); +} + +DHPy debug_ctx_Bytes_FromStringAndSize(HPyContext dctx, const char *v, HPy_ssize_t len) +{ + return DHPy_wrap(dctx, HPyBytes_FromStringAndSize(get_info(dctx)->uctx, v, len)); +} + +DHPy debug_ctx_Unicode_FromString(HPyContext dctx, const char *utf8) +{ + return DHPy_wrap(dctx, HPyUnicode_FromString(get_info(dctx)->uctx, utf8)); +} + +int debug_ctx_Unicode_Check(HPyContext dctx, DHPy h) +{ + return HPyUnicode_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_Unicode_AsUTF8String(HPyContext dctx, DHPy h) +{ + return DHPy_wrap(dctx, HPyUnicode_AsUTF8String(get_info(dctx)->uctx, DHPy_unwrap(h))); +} + +DHPy debug_ctx_Unicode_FromWideChar(HPyContext dctx, const wchar_t *w, HPy_ssize_t size) +{ + return DHPy_wrap(dctx, HPyUnicode_FromWideChar(get_info(dctx)->uctx, w, size)); +} + +int debug_ctx_List_Check(HPyContext dctx, DHPy h) +{ + return HPyList_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_List_New(HPyContext dctx, HPy_ssize_t len) +{ + return DHPy_wrap(dctx, HPyList_New(get_info(dctx)->uctx, len)); +} + +int debug_ctx_List_Append(HPyContext dctx, DHPy h_list, DHPy h_item) +{ + return HPyList_Append(get_info(dctx)->uctx, DHPy_unwrap(h_list), DHPy_unwrap(h_item)); +} + +int debug_ctx_Dict_Check(HPyContext dctx, DHPy h) +{ + return HPyDict_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_Dict_New(HPyContext dctx) +{ + return DHPy_wrap(dctx, HPyDict_New(get_info(dctx)->uctx)); +} + +int debug_ctx_Tuple_Check(HPyContext dctx, DHPy h) +{ + return HPyTuple_Check(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +DHPy debug_ctx_FromPyObject(HPyContext dctx, cpy_PyObject *obj) +{ + return DHPy_wrap(dctx, HPy_FromPyObject(get_info(dctx)->uctx, obj)); +} + +cpy_PyObject *debug_ctx_AsPyObject(HPyContext dctx, DHPy h) +{ + return HPy_AsPyObject(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + +void debug_ctx_CallDestroyAndThenDealloc(HPyContext dctx, void *func, cpy_PyObject *self) +{ + _HPy_CallDestroyAndThenDealloc(get_info(dctx)->uctx, func, self); +} + +HPyListBuilder debug_ctx_ListBuilder_New(HPyContext dctx, HPy_ssize_t initial_size) +{ + return HPyListBuilder_New(get_info(dctx)->uctx, initial_size); +} + +void debug_ctx_ListBuilder_Set(HPyContext dctx, HPyListBuilder builder, HPy_ssize_t index, DHPy h_item) +{ + HPyListBuilder_Set(get_info(dctx)->uctx, builder, index, DHPy_unwrap(h_item)); +} + +DHPy debug_ctx_ListBuilder_Build(HPyContext dctx, HPyListBuilder builder) +{ + return DHPy_wrap(dctx, HPyListBuilder_Build(get_info(dctx)->uctx, builder)); +} + +void debug_ctx_ListBuilder_Cancel(HPyContext dctx, HPyListBuilder builder) +{ + HPyListBuilder_Cancel(get_info(dctx)->uctx, builder); +} + +HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext dctx, HPy_ssize_t initial_size) +{ + return HPyTupleBuilder_New(get_info(dctx)->uctx, initial_size); +} + +void debug_ctx_TupleBuilder_Set(HPyContext dctx, HPyTupleBuilder builder, HPy_ssize_t index, DHPy h_item) +{ + HPyTupleBuilder_Set(get_info(dctx)->uctx, builder, index, DHPy_unwrap(h_item)); +} + +DHPy debug_ctx_TupleBuilder_Build(HPyContext dctx, HPyTupleBuilder builder) +{ + return DHPy_wrap(dctx, HPyTupleBuilder_Build(get_info(dctx)->uctx, builder)); +} + +void debug_ctx_TupleBuilder_Cancel(HPyContext dctx, HPyTupleBuilder builder) +{ + HPyTupleBuilder_Cancel(get_info(dctx)->uctx, builder); +} + +HPyTracker debug_ctx_Tracker_New(HPyContext dctx, HPy_ssize_t size) +{ + return HPyTracker_New(get_info(dctx)->uctx, size); +} + +int debug_ctx_Tracker_Add(HPyContext dctx, HPyTracker ht, DHPy h) +{ + return HPyTracker_Add(get_info(dctx)->uctx, ht, DHPy_unwrap(h)); +} + +void debug_ctx_Tracker_ForgetAll(HPyContext dctx, HPyTracker ht) +{ + HPyTracker_ForgetAll(get_info(dctx)->uctx, ht); +} + +void debug_ctx_Tracker_Close(HPyContext dctx, HPyTracker ht) +{ + HPyTracker_Close(get_info(dctx)->uctx, ht); +} + +void debug_ctx_Dump(HPyContext dctx, DHPy h) +{ + _HPy_Dump(get_info(dctx)->uctx, DHPy_unwrap(h)); +} + diff --git a/hpy/debug/src/debug_ctx.c b/hpy/debug/src/debug_ctx.c new file mode 100644 index 000000000..aab004c64 --- /dev/null +++ b/hpy/debug/src/debug_ctx.c @@ -0,0 +1,121 @@ +#include +#include +#include "debug_internal.h" +#include "autogen_debug_ctx_init.h" + +static struct _HPyContext_s g_debug_ctx = { + .name = "HPy Debug Mode ABI", + ._private = NULL, + .ctx_version = 1, +}; + +// NOTE: at the moment this function assumes that uctx is always the +// same. If/when we migrate to a system in which we can have multiple +// independent contexts, this function should ensure to create a different +// debug wrapper for each of them. +static int debug_ctx_init(HPyContext dctx, HPyContext uctx) +{ + if (dctx->_private != NULL) { + // already initialized + assert(get_info(dctx)->uctx == uctx); // sanity check + return 0; + } + // initialize debug_info + // XXX: currently we never free this malloc + HPyDebugInfo *info = malloc(sizeof(HPyDebugInfo)); + if (info == NULL) { + HPyErr_NoMemory(uctx); + return -1; + } + info->magic_number = HPY_DEBUG_MAGIC; + info->uctx = uctx; + info->current_generation = 0; + info->open_handles = NULL; + //info->closed_handles = NULL; + dctx->_private = info; + + debug_ctx_init_fields(dctx, uctx); + return 0; +} + +HPyContext hpy_debug_get_ctx(HPyContext uctx) +{ + HPyContext dctx = &g_debug_ctx; + if (debug_ctx_init(dctx, uctx) < 0) + return NULL; + return dctx; +} + +// this function is supposed to be called from gdb: it tries to determine +// whether a handle is universal or debug by looking at the last bit +extern struct _HPyContext_s g_universal_ctx; +__attribute__((unused)) static void hpy_magic_dump(HPy h) +{ + int universal = h._i & 1; + if (universal) + fprintf(stderr, "\nUniversal handle\n"); + else + fprintf(stderr, "\nDebug handle\n"); + + fprintf(stderr, "raw value: %lx (%ld)\n", h._i, h._i); + if (universal) + _HPy_Dump(&g_universal_ctx, h); + else { + DebugHandle *dh = as_DebugHandle(h); + fprintf(stderr, "dh->uh: %lx\n", dh->uh._i); + _HPy_Dump(&g_universal_ctx, dh->uh); + } +} + +/* ~~~~~~~~~~ manually written wrappers ~~~~~~~~~~ */ + +void debug_ctx_Close(HPyContext dctx, DHPy dh) +{ + UHPy uh = DHPy_unwrap(dh); + DHPy_close(dctx, dh); + HPy_Close(get_info(dctx)->uctx, uh); +} + +DHPy debug_ctx_Tuple_FromArray(HPyContext dctx, DHPy dh_items[], HPy_ssize_t n) +{ + // NOTE: replace VLAs with alloca() once issue #157 is fixed + UHPy uh_items[n]; + for(int i=0; iuctx, uh_items, n)); +} + +DHPy debug_ctx_Type_GenericNew(HPyContext dctx, DHPy dh_type, DHPy *dh_args, + HPy_ssize_t nargs, DHPy dh_kw) +{ + UHPy uh_type = DHPy_unwrap(dh_type); + UHPy uh_kw = DHPy_unwrap(dh_kw); + // NOTE: replace VLAs with alloca() once issue #157 is fixed + UHPy uh_args[nargs]; + for(int i=0; iuctx, uh_type, uh_args, + nargs, uh_kw)); +} + +DHPy debug_ctx_Type_FromSpec(HPyContext dctx, HPyType_Spec *spec, HPyType_SpecParam *dparams) +{ + // dparams might contain some hidden DHPy: we need to manually unwrap them. + if (dparams != NULL) { + // count the params + HPy_ssize_t n = 1; + for (HPyType_SpecParam *p = dparams; p->kind != 0; p++) { + n++; + } + // NOTE: replace VLAs with alloca() once issue #157 is fixed + HPyType_SpecParam uparams[n]; + for (HPy_ssize_t i=0; iuctx, spec, uparams)); + } + return DHPy_wrap(dctx, HPyType_FromSpec(get_info(dctx)->uctx, spec, NULL)); +} diff --git a/hpy/debug/src/debug_ctx_cpython.c b/hpy/debug/src/debug_ctx_cpython.c new file mode 100644 index 000000000..de902ad1b --- /dev/null +++ b/hpy/debug/src/debug_ctx_cpython.c @@ -0,0 +1,121 @@ +/* =========== CPython-ONLY =========== + In the following code, we use _py2h and _h2py and we assumed they are the + ones defined by CPython's version of hpy.universal. + + DO NOT COMPILE THIS FILE UNLESS YOU ARE BUILDING CPython's hpy.universal. + + If you want to compile the debug mode into your own non-CPython version of + hpy.universal, you should include debug_ctx_not_cpython.c. + ==================================== + + In theory, the debug mode is completely generic and can wrap a generic + uctx. However, CPython is special because it does not have native support + for HPy, so uctx contains the logic to call HPy functions from CPython, by + using _HPy_CallRealFunctionFromTrampoline. + + uctx->ctx_CallRealFunctionFromTrampoline convers PyObject* into UHPy. So + for the debug mode we need to: + + 1. convert the PyObject* args into UHPys. + 2. wrap the UHPys into DHPys. + 3. unwrap the resulting DHPy and convert to PyObject*. +*/ + +#include +#include "debug_internal.h" +#include "handles.h" // for _py2h and _h2py + +static inline DHPy _py2dh(HPyContext dctx, PyObject *obj) +{ + return DHPy_wrap(dctx, _py2h(obj)); +} + +static inline PyObject *_dh2py(DHPy dh) +{ + return _h2py(DHPy_unwrap(dh)); +} + +void debug_ctx_CallRealFunctionFromTrampoline(HPyContext dctx, + HPyFunc_Signature sig, + void *func, void *args) +{ + switch (sig) { + case HPyFunc_NOARGS: { + HPyFunc_noargs f = (HPyFunc_noargs)func; + _HPyFunc_args_NOARGS *a = (_HPyFunc_args_NOARGS*)args; + DHPy dh_self = _py2dh(dctx, a->self); + DHPy dh_result = f(dctx, dh_self); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_self); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_O: { + HPyFunc_o f = (HPyFunc_o)func; + _HPyFunc_args_O *a = (_HPyFunc_args_O*)args; + DHPy dh_self = _py2dh(dctx, a->self); + DHPy dh_arg = _py2dh(dctx, a->arg); + DHPy dh_result = f(dctx, dh_self, dh_arg); + a->result = _dh2py(dh_result); + DHPy_close(dctx, dh_self); + DHPy_close(dctx, dh_arg); + DHPy_close(dctx, dh_result); + return; + } + case HPyFunc_VARARGS: { + HPyFunc_varargs f = (HPyFunc_varargs)func; + _HPyFunc_args_VARARGS *a = (_HPyFunc_args_VARARGS*)args; + DHPy dh_self = _py2dh(dctx, a->self); + Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); + DHPy dh_args[nargs * sizeof(DHPy)]; + for (Py_ssize_t i = 0; i < nargs; i++) { + dh_args[i] = _py2dh(dctx, PyTuple_GET_ITEM(a->args, i)); + } + a->result = _dh2py(f(dctx, dh_self, dh_args, nargs)); + DHPy_close(dctx, dh_self); + for (Py_ssize_t i = 0; i < nargs; i++) { + DHPy_close(dctx, dh_args[i]); + } + return; + } + case HPyFunc_KEYWORDS: { + HPyFunc_keywords f = (HPyFunc_keywords)func; + _HPyFunc_args_KEYWORDS *a = (_HPyFunc_args_KEYWORDS*)args; + DHPy dh_self = _py2dh(dctx, a->self); + Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); + DHPy dh_args[nargs * sizeof(DHPy)]; + for (Py_ssize_t i = 0; i < nargs; i++) { + dh_args[i] = _py2dh(dctx, PyTuple_GET_ITEM(a->args, i)); + } + DHPy dh_kw = _py2dh(dctx, a->kw); + a->result = _dh2py(f(dctx, dh_self, dh_args, nargs, dh_kw)); + DHPy_close(dctx, dh_self); + for (Py_ssize_t i = 0; i < nargs; i++) { + DHPy_close(dctx, dh_args[i]); + } + DHPy_close(dctx, dh_kw); + return; + } + case HPyFunc_INITPROC: { + HPyFunc_initproc f = (HPyFunc_initproc)func; + _HPyFunc_args_INITPROC *a = (_HPyFunc_args_INITPROC*)args; + DHPy dh_self = _py2dh(dctx, a->self); + Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); + DHPy dh_args[nargs * sizeof(DHPy)]; + for (Py_ssize_t i = 0; i < nargs; i++) { + dh_args[i] = _py2dh(dctx, PyTuple_GET_ITEM(a->args, i)); + } + DHPy dh_kw = _py2dh(dctx, a->kw); + a->result = f(dctx, dh_self, dh_args, nargs, dh_kw); + DHPy_close(dctx, dh_self); + for (Py_ssize_t i = 0; i < nargs; i++) { + DHPy_close(dctx, dh_args[i]); + } + DHPy_close(dctx, dh_kw); + return; + } +#include "autogen_debug_ctx_call.i" + default: + abort(); // XXX + } +} diff --git a/hpy/debug/src/debug_ctx_not_cpython.c b/hpy/debug/src/debug_ctx_not_cpython.c new file mode 100644 index 000000000..16bc5c1fa --- /dev/null +++ b/hpy/debug/src/debug_ctx_not_cpython.c @@ -0,0 +1,16 @@ +// This is for non-CPython implementations! +// +// If you want to bundle the debug mode into your own version of +// hpy.universal, make sure to compile this file and NOT debug_ctx_cpython.c + +#include "debug_internal.h" + +void debug_ctx_CallRealFunctionFromTrampoline(HPyContext dctx, + HPyFunc_Signature sig, + void *func, void *args) +{ + HPyContext uctx = get_info(dctx)->uctx; + HPy_FatalError(uctx, + "Something is very wrong! _HPy_CallRealFunctionFromTrampoline() " + "should be used only by the CPython version of hpy.universal"); +} diff --git a/hpy/debug/src/debug_handles.c b/hpy/debug/src/debug_handles.c new file mode 100644 index 000000000..c3bcf8cdf --- /dev/null +++ b/hpy/debug/src/debug_handles.c @@ -0,0 +1,52 @@ +#include "debug_internal.h" + +DHPy DHPy_wrap(HPyContext dctx, UHPy uh) +{ + UHPy_sanity_check(uh); + if (HPy_IsNull(uh)) + return HPy_NULL; + HPyDebugInfo *info = get_info(dctx); + DebugHandle *handle = malloc(sizeof(DebugHandle)); + if (handle == NULL) { + return HPyErr_NoMemory(info->uctx); + } + handle->uh = uh; + handle->generation = info->current_generation; + handle->prev = NULL; + handle->next = info->open_handles; + if (info->open_handles) + info->open_handles->prev = handle; + info->open_handles = handle; + return as_DHPy(handle); +} + +void DHPy_close(HPyContext dctx, DHPy dh) +{ + DHPy_sanity_check(dh); + if (HPy_IsNull(dh)) + return; + HPyDebugInfo *info = get_info(dctx); + DebugHandle *handle = as_DebugHandle(dh); + + // remove the handle from the open_handles list + if (handle->prev) + handle->prev->next = handle->next; + if (handle->next) + handle->next->prev = handle->prev; + if (info->open_handles == handle) + info->open_handles = handle->next; + + // TODO: eventually, we want to keep a list of closed handles to be able + // to detect if you are still using them. + DHPy_free(dh); +} + +void DHPy_free(DHPy dh) +{ + DHPy_sanity_check(dh); + DebugHandle *handle = as_DebugHandle(dh); + // this is not strictly necessary, but it increases the chances that you + // get a clear segfault if you use a freed handle + handle->uh = HPy_NULL; + free(handle); +} diff --git a/hpy/debug/src/debug_internal.h b/hpy/debug/src/debug_internal.h new file mode 100644 index 000000000..9791c348e --- /dev/null +++ b/hpy/debug/src/debug_internal.h @@ -0,0 +1,113 @@ +/* Internal header for all the files in hpy/debug/src. The public API is in + include/hpy_debug.h +*/ +#ifndef HPY_DEBUG_INTERNAL_H +#define HPY_DEBUG_INTERNAL_H + +#include +#include "hpy.h" +#include "hpy_debug.h" + +#define HPY_DEBUG_MAGIC 0xDEB00FF + +/* The Debug context is a wrapper around an underlying context, which we will + call Universal. Inside the debug mode we manipulate handles which belongs + to both contexts, so to make things easier we create two typedefs to make + it clear what kind of handle we expect: UHPy and DHPy: + + * UHPy are opaque from our point of view. + + * DHPy are actually DebugHandle* in disguise. DebugHandles are wrappers + around a UHPy, with a bunch of extra info. + + To cast between DHPy and DebugHandle*, use as_DebugHandle and as_DHPy: + these are just no-op casts. + + To wrap a UHPy, call DHPy_wrap: this contains some actual logic, because it + malloc()s a new DebugHandle, which will be released at some point in the + future after we call HPy_Close on it. Note that if you call DHPy_wrap + twice on the same UHPy, you get two different DHPy. + + To unwrap a DHPy and get the underyling UHPy, call DHPy_unwrap. If you call + DHPy_unwrap multiple times on the same DHPy, you always get the same UHPy. + + WARNING: both UHPy and DHPy are alias of HPy, so we need to take care of + not mixing them, because the compiler cannot help. + + Each DebugHandle has a "generation", which is just a int to be able to get + only the handles which were created after a certain point. +*/ + +typedef HPy UHPy; +typedef HPy DHPy; + +/* Under CPython: + - UHPy always end with 1 (see hpy.universal's _py2h and _h2py) + - DHPy are pointers, so they always end with 0 + + DHPy_sanity_check is a minimal check to ensure that we are not treating a + UHPy as a DHPy. Note that DHPy_sanity_check works fine also on HPy_NULL. + + NOTE: UHPy_sanity_check works ONLY with CPython's hpy.universal. If you + bundle the debug mode in an alternative Python implementation, you should + probably change/override UHPy_sanity_check, possibly with an #ifdef. +*/ +static inline void DHPy_sanity_check(DHPy dh) { + assert( (dh._i & 1) == 0 ); +} + +static inline void UHPy_sanity_check(UHPy uh) { + if (!HPy_IsNull(uh)) + assert( (uh._i & 1) == 1 ); +} + +// NOTE: having a "generation" field is the easiest way to know when a handle +// was created, but we waste 8 bytes per handle. Since all handles of the same +// generation are stored sequentially in the open_handles list, a possible +// alternative implementation is to put special placeholders inside the list +// to mark the creation of a new generation +typedef struct DebugHandle { + UHPy uh; + long generation; + struct DebugHandle *prev; + struct DebugHandle *next; +} DebugHandle; + +static inline DebugHandle * as_DebugHandle(DHPy dh) { + DHPy_sanity_check(dh); + return (DebugHandle *)dh._i; +} + +static inline DHPy as_DHPy(DebugHandle *handle) { + return (DHPy){(HPy_ssize_t)handle}; +} + +DHPy DHPy_wrap(HPyContext dctx, UHPy uh); +void DHPy_close(HPyContext dctx, DHPy dh); +void DHPy_free(DHPy dh); + +static inline UHPy DHPy_unwrap(DHPy dh) { + if (HPy_IsNull(dh)) + return HPy_NULL; + return as_DebugHandle(dh)->uh; +} + +/* === HPyDebugInfo === */ + +typedef struct { + long magic_number; // used just for sanity checks + HPyContext uctx; + long current_generation; + DebugHandle *open_handles; // linked list + //DebugHandle *closed_handles; // linked list +} HPyDebugInfo; + +static inline HPyDebugInfo *get_info(HPyContext dctx) +{ + HPyDebugInfo *info = (HPyDebugInfo*)dctx->_private; + assert(info->magic_number == HPY_DEBUG_MAGIC); // sanity check + return info; +} + + +#endif /* HPY_DEBUG_INTERNAL_H */ diff --git a/hpy/debug/src/include/hpy_debug.h b/hpy/debug/src/include/hpy_debug.h new file mode 100644 index 000000000..f036299e3 --- /dev/null +++ b/hpy/debug/src/include/hpy_debug.h @@ -0,0 +1,14 @@ +#ifndef HPY_DEBUG_H +#define HPY_DEBUG_H + +#include "hpy.h" + +HPyContext hpy_debug_get_ctx(HPyContext original_ctx); + +// this is the HPy init function created by HPy_MODINIT. In CPython's version +// of hpy.universal the code is embedded inside the extension, so we can call +// this function directly instead of dlopen it. This is similar to what +// CPython does for its own built-in modules +HPy HPyInit__debug(HPyContext uctx); + +#endif /* HPY_DEBUG_H */ diff --git a/hpy/devel/__init__.py b/hpy/devel/__init__.py index 8c8800454..35938620f 100644 --- a/hpy/devel/__init__.py +++ b/hpy/devel/__init__.py @@ -100,17 +100,11 @@ def handle_hpy_ext_modules(dist, attr, hpy_ext_modules): _HPY_UNIVERSAL_MODULE_STUB_TEMPLATE = """ -class Spec: - def __init__(self, name, origin): - self.name = name - self.origin = origin - - def __bootstrap__(): import sys, pkg_resources - from hpy.universal import load_from_spec + from hpy.universal import load ext_filepath = pkg_resources.resource_filename(__name__, {ext_file!r}) - m = load_from_spec(Spec({module_name!r}, ext_filepath)) + m = load({module_name!r}, ext_filepath) m.__file__ = ext_filepath m.__loader__ = __loader__ m.__package__ = __package__ @@ -204,9 +198,12 @@ def _finalize_hpy_ext(self, ext): if ext.hpy_abi == 'cpython': ext.sources += self.hpydevel.get_ctx_sources() ext._hpy_needs_stub = False - if ext.hpy_abi == 'universal': + elif ext.hpy_abi == 'universal': ext.define_macros.append(('HPY_UNIVERSAL_ABI', None)) ext._hpy_needs_stub = True + else: + raise DistutilsError('Unknown HPy ABI: %s. Valid values are: ' + 'cpython, universal' % ext.hpy_abi) def finalize_options(self): self._extensions = self.distribution.ext_modules or [] diff --git a/hpy/devel/include/cpython/hpy.h b/hpy/devel/include/cpython/hpy.h index 4269f8aee..c99403944 100644 --- a/hpy/devel/include/cpython/hpy.h +++ b/hpy/devel/include/cpython/hpy.h @@ -45,10 +45,13 @@ typedef Py_hash_t HPy_hash_t; // this should maybe autogenerated from public_api.h typedef struct _HPyContext_s { + const char *name; /* Constants */ HPy h_None; HPy h_True; HPy h_False; + HPy h_NotImplemented; + HPy h_Ellipsis; /* Exceptions */ HPy h_BaseException; HPy h_Exception; @@ -140,13 +143,14 @@ static inline void* HPy_AsVoidP(HPy h) { return (void*)h._o; } HPyAPI_FUNC(HPyContext) _HPyGetContext(void) { HPyContext ctx = &_global_ctx; - if (HPy_IsNull(ctx->h_None)) { - // XXX: we need to find a better way to check whether the ctx is - // initialized or not + if (!ctx->name) { + ctx->name = "HPy CPython ABI", /* Constants */ ctx->h_None = _py2h(Py_None); ctx->h_True = _py2h(Py_True); ctx->h_False = _py2h(Py_False); + ctx->h_NotImplemented = _py2h(Py_NotImplemented); + ctx->h_Ellipsis = _py2h(Py_Ellipsis); /* Exceptions */ ctx->h_BaseException = _py2h(PyExc_BaseException); ctx->h_Exception = _py2h(PyExc_Exception); diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index 922abc28b..8adf4e5e4 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -11,10 +11,14 @@ */ struct _HPyContext_s { + const char *name; // used just to make debugging and testing easier + void *_private; // used by implementations to store custom data int ctx_version; HPy h_None; HPy h_True; HPy h_False; + HPy h_NotImplemented; + HPy h_Ellipsis; HPy h_BaseException; HPy h_Exception; HPy h_StopAsyncIteration; diff --git a/hpy/tools/autogen/__main__.py b/hpy/tools/autogen/__main__.py index 62b0d8699..8f983c625 100644 --- a/hpy/tools/autogen/__main__.py +++ b/hpy/tools/autogen/__main__.py @@ -16,6 +16,7 @@ from .hpyfunc import autogen_ctx_call_i from .hpyfunc import autogen_cpython_hpyfunc_trampoline_h from .hpyslot import autogen_hpyslot_h +from .debug import autogen_debug_ctx_init_h, autogen_debug_wrappers, autogen_debug_ctx_call_i from .pypy import autogen_pypy_txt def main(): @@ -37,6 +38,9 @@ def main(): autogen_ctx_call_i, autogen_cpython_hpyfunc_trampoline_h, autogen_hpyslot_h, + autogen_debug_ctx_init_h, + autogen_debug_wrappers, + autogen_debug_ctx_call_i, autogen_pypy_txt): cls(api).write(outdir) diff --git a/hpy/tools/autogen/ctx.py b/hpy/tools/autogen/ctx.py index cedfef0e5..6d7adb2af 100644 --- a/hpy/tools/autogen/ctx.py +++ b/hpy/tools/autogen/ctx.py @@ -8,6 +8,8 @@ class autogen_ctx_h(AutoGenFile): PATH = 'hpy/devel/include/universal/autogen_ctx.h' ## struct _HPyContext_s { + ## const char *name; + ## void *_private; ## int ctx_version; ## HPy h_None; ## ... @@ -19,6 +21,8 @@ def generate(self): lines = [] w = lines.append w('struct _HPyContext_s {') + w(' const char *name; // used just to make debugging and testing easier') + w(' void *_private; // used by implementations to store custom data') w(' int ctx_version;') for var in self.api.variables: w(' %s;' % self.declare_var(var)) @@ -45,7 +49,9 @@ def declare_func(self, func): class autogen_ctx_def_h(AutoGenFile): PATH = 'hpy/universal/src/autogen_ctx_def.h' - ## struct _HPyContext_s global_ctx = { + ## struct _HPyContext_s g_universal_ctx = { + ## .name = "...", + ## ._private = NULL, ## .ctx_version = 1, ## .h_None = {CONSTANT_H_NONE}, ## ... @@ -56,10 +62,11 @@ class autogen_ctx_def_h(AutoGenFile): def generate(self): lines = [] w = lines.append - w('struct _HPyContext_s global_ctx = {') + w('struct _HPyContext_s g_universal_ctx = {') + w(' .name = "HPy Universal ABI (CPython backend)",') + w(' ._private = NULL,') w(' .ctx_version = 1,') - for var in self.api.variables: - w(' .%s = {CONSTANT_%s},' % (var.name, var.name.upper())) + w(' /* h_None & co. are initialized by init_universal_ctx() */') for func in self.api.functions: w(' .%s = &%s,' % (func.ctx_name(), func.ctx_name())) w('};') diff --git a/hpy/tools/autogen/debug.py b/hpy/tools/autogen/debug.py new file mode 100644 index 000000000..3eb1bc096 --- /dev/null +++ b/hpy/tools/autogen/debug.py @@ -0,0 +1,164 @@ +from copy import deepcopy +import textwrap +from pycparser import c_ast +from .autogenfile import AutoGenFile +from .parse import toC, find_typedecl +from .hpyfunc import NO_CALL + +class HPy_2_DHPy_Visitor(c_ast.NodeVisitor): + "Visitor which renames all HPy types to DHPy" + + def visit_IdentifierType(self, node): + if node.names == ['HPy']: + node.names = ['DHPy'] + + def visit_TypeDecl(self, node): + if node.declname == 'ctx': + node.declname = 'dctx' + self.generic_visit(node) + +def funcnode_with_new_name(node, name): + newnode = deepcopy(node) + typedecl = find_typedecl(newnode) + typedecl.declname = name + return newnode + +def get_debug_wrapper_node(func): + newnode = funcnode_with_new_name(func.node, 'debug_%s' % func.ctx_name()) + # fix all the types + visitor = HPy_2_DHPy_Visitor() + visitor.visit(newnode) + return newnode + + +class autogen_debug_ctx_init_h(AutoGenFile): + PATH = 'hpy/debug/src/autogen_debug_ctx_init.h' + + def generate(self): + lines = [] + w = lines.append + # emit the declarations for all the debug_ctx_* functions + for func in self.api.functions: + w(toC(get_debug_wrapper_node(func)) + ';') + w('') + w('static inline void debug_ctx_init_fields(HPyContext dctx, HPyContext uctx)') + w('{') + for var in self.api.variables: + name = var.name + w(f' dctx->{name} = DHPy_wrap(dctx, uctx->{name});') + for func in self.api.functions: + name = func.ctx_name() + w(f' dctx->{name} = &debug_{name};') + + w('}') + return '\n'.join(lines) + + +class autogen_debug_wrappers(AutoGenFile): + PATH = 'hpy/debug/src/autogen_debug_wrappers.c' + + NO_WRAPPER = set([ + '_HPy_CallRealFunctionFromTrampoline', + 'HPy_Close', + 'HPyTuple_FromArray', + 'HPyType_GenericNew', + 'HPyType_FromSpec', + ]) + + def generate(self): + lines = [] + w = lines.append + w('#include "debug_internal.h"') + w('') + for func in self.api.functions: + debug_wrapper = self.gen_debug_wrapper(func) + if debug_wrapper: + w(debug_wrapper) + w('') + return '\n'.join(lines) + + def gen_debug_wrapper(self, func): + if func.name in self.NO_WRAPPER: + return + # + assert not func.is_varargs() + node = get_debug_wrapper_node(func) + signature = toC(node) + rettype = toC(node.type.type) + # + def get_params(): + lst = [] + for p in node.type.args.params: + if p.name == 'ctx': + lst.append('get_info(dctx)->uctx') + elif toC(p.type) == 'DHPy': + lst.append('DHPy_unwrap(%s)' % p.name) + elif toC(p.type) in ('DHPy *', 'DHPy []'): + assert False, ('C type %s not supported, please write the wrapper ' + 'for %s by hand' % (toC(p.type), func.name)) + else: + lst.append(p.name) + return ', '.join(lst) + params = get_params() + # + lines = [] + w = lines.append + w(signature) + w('{') + if rettype == 'void': + w(f' {func.name}({params});') + elif rettype == 'DHPy': + w(f' return DHPy_wrap(dctx, {func.name}({params}));') + else: + w(f' return {func.name}({params});') + w('}') + return '\n'.join(lines) + + +class autogen_debug_ctx_call_i(AutoGenFile): + PATH = 'hpy/debug/src/autogen_debug_ctx_call.i' + + def generate(self): + lines = [] + w = lines.append + for hpyfunc in self.api.hpyfunc_typedefs: + name = hpyfunc.base_name() + NAME = name.upper() + if NAME in NO_CALL: + continue + # + c_ret_type = toC(hpyfunc.return_type()) + args = ['dctx'] + dhpys = [] + for i, param in enumerate(hpyfunc.params()[1:]): + pname = param.name + if pname is None: + pname = 'arg%d' % i + if toC(param.type) == 'HPy': + dhpys.append(pname) + args.append(f'dh_{pname}') + else: + args.append(f'a->{pname}') + args = ', '.join(args) + # + w(f' case HPyFunc_{NAME}: {{') + w(f' HPyFunc_{name} f = (HPyFunc_{name})func;') + w(f' _HPyFunc_args_{NAME} *a = (_HPyFunc_args_{NAME}*)args;') + for pname in dhpys: + w(f' DHPy dh_{pname} = _py2dh(dctx, a->{pname});') + # + if c_ret_type == 'void': + w(f' f({args});') + elif c_ret_type == 'HPy': + w(f' DHPy dh_result = f({args});') + w(f' a->result = _dh2py(dh_result);') + dhpys.append('result') + else: + w(f' a->result = f({args});') + # + for pname in dhpys: + w(f' DHPy_close(dctx, dh_{pname});') + # + w(f' return;') + w(f' }}') + return '\n'.join(lines) diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 3acbb1f26..40d8da002 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -23,6 +23,8 @@ typedef int HPy_RichCmpOp; HPy h_None; HPy h_True; HPy h_False; +HPy h_NotImplemented; +HPy h_Ellipsis; /* Exceptions */ HPy h_BaseException; diff --git a/hpy/universal/src/api.h b/hpy/universal/src/api.h index 555bec3a1..7db2ffa71 100644 --- a/hpy/universal/src/api.h +++ b/hpy/universal/src/api.h @@ -4,6 +4,6 @@ #include "hpy.h" #define HPyAPI_STORAGE _HPy_HIDDEN -extern struct _HPyContext_s global_ctx; +extern struct _HPyContext_s g_universal_ctx; #endif /* HPY_API_H */ diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 9eee68a00..75fd0c800 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -10,81 +10,11 @@ */ -struct _HPyContext_s global_ctx = { +struct _HPyContext_s g_universal_ctx = { + .name = "HPy Universal ABI (CPython backend)", + ._private = NULL, .ctx_version = 1, - .h_None = {CONSTANT_H_NONE}, - .h_True = {CONSTANT_H_TRUE}, - .h_False = {CONSTANT_H_FALSE}, - .h_BaseException = {CONSTANT_H_BASEEXCEPTION}, - .h_Exception = {CONSTANT_H_EXCEPTION}, - .h_StopAsyncIteration = {CONSTANT_H_STOPASYNCITERATION}, - .h_StopIteration = {CONSTANT_H_STOPITERATION}, - .h_GeneratorExit = {CONSTANT_H_GENERATOREXIT}, - .h_ArithmeticError = {CONSTANT_H_ARITHMETICERROR}, - .h_LookupError = {CONSTANT_H_LOOKUPERROR}, - .h_AssertionError = {CONSTANT_H_ASSERTIONERROR}, - .h_AttributeError = {CONSTANT_H_ATTRIBUTEERROR}, - .h_BufferError = {CONSTANT_H_BUFFERERROR}, - .h_EOFError = {CONSTANT_H_EOFERROR}, - .h_FloatingPointError = {CONSTANT_H_FLOATINGPOINTERROR}, - .h_OSError = {CONSTANT_H_OSERROR}, - .h_ImportError = {CONSTANT_H_IMPORTERROR}, - .h_ModuleNotFoundError = {CONSTANT_H_MODULENOTFOUNDERROR}, - .h_IndexError = {CONSTANT_H_INDEXERROR}, - .h_KeyError = {CONSTANT_H_KEYERROR}, - .h_KeyboardInterrupt = {CONSTANT_H_KEYBOARDINTERRUPT}, - .h_MemoryError = {CONSTANT_H_MEMORYERROR}, - .h_NameError = {CONSTANT_H_NAMEERROR}, - .h_OverflowError = {CONSTANT_H_OVERFLOWERROR}, - .h_RuntimeError = {CONSTANT_H_RUNTIMEERROR}, - .h_RecursionError = {CONSTANT_H_RECURSIONERROR}, - .h_NotImplementedError = {CONSTANT_H_NOTIMPLEMENTEDERROR}, - .h_SyntaxError = {CONSTANT_H_SYNTAXERROR}, - .h_IndentationError = {CONSTANT_H_INDENTATIONERROR}, - .h_TabError = {CONSTANT_H_TABERROR}, - .h_ReferenceError = {CONSTANT_H_REFERENCEERROR}, - .h_SystemError = {CONSTANT_H_SYSTEMERROR}, - .h_SystemExit = {CONSTANT_H_SYSTEMEXIT}, - .h_TypeError = {CONSTANT_H_TYPEERROR}, - .h_UnboundLocalError = {CONSTANT_H_UNBOUNDLOCALERROR}, - .h_UnicodeError = {CONSTANT_H_UNICODEERROR}, - .h_UnicodeEncodeError = {CONSTANT_H_UNICODEENCODEERROR}, - .h_UnicodeDecodeError = {CONSTANT_H_UNICODEDECODEERROR}, - .h_UnicodeTranslateError = {CONSTANT_H_UNICODETRANSLATEERROR}, - .h_ValueError = {CONSTANT_H_VALUEERROR}, - .h_ZeroDivisionError = {CONSTANT_H_ZERODIVISIONERROR}, - .h_BlockingIOError = {CONSTANT_H_BLOCKINGIOERROR}, - .h_BrokenPipeError = {CONSTANT_H_BROKENPIPEERROR}, - .h_ChildProcessError = {CONSTANT_H_CHILDPROCESSERROR}, - .h_ConnectionError = {CONSTANT_H_CONNECTIONERROR}, - .h_ConnectionAbortedError = {CONSTANT_H_CONNECTIONABORTEDERROR}, - .h_ConnectionRefusedError = {CONSTANT_H_CONNECTIONREFUSEDERROR}, - .h_ConnectionResetError = {CONSTANT_H_CONNECTIONRESETERROR}, - .h_FileExistsError = {CONSTANT_H_FILEEXISTSERROR}, - .h_FileNotFoundError = {CONSTANT_H_FILENOTFOUNDERROR}, - .h_InterruptedError = {CONSTANT_H_INTERRUPTEDERROR}, - .h_IsADirectoryError = {CONSTANT_H_ISADIRECTORYERROR}, - .h_NotADirectoryError = {CONSTANT_H_NOTADIRECTORYERROR}, - .h_PermissionError = {CONSTANT_H_PERMISSIONERROR}, - .h_ProcessLookupError = {CONSTANT_H_PROCESSLOOKUPERROR}, - .h_TimeoutError = {CONSTANT_H_TIMEOUTERROR}, - .h_Warning = {CONSTANT_H_WARNING}, - .h_UserWarning = {CONSTANT_H_USERWARNING}, - .h_DeprecationWarning = {CONSTANT_H_DEPRECATIONWARNING}, - .h_PendingDeprecationWarning = {CONSTANT_H_PENDINGDEPRECATIONWARNING}, - .h_SyntaxWarning = {CONSTANT_H_SYNTAXWARNING}, - .h_RuntimeWarning = {CONSTANT_H_RUNTIMEWARNING}, - .h_FutureWarning = {CONSTANT_H_FUTUREWARNING}, - .h_ImportWarning = {CONSTANT_H_IMPORTWARNING}, - .h_UnicodeWarning = {CONSTANT_H_UNICODEWARNING}, - .h_BytesWarning = {CONSTANT_H_BYTESWARNING}, - .h_ResourceWarning = {CONSTANT_H_RESOURCEWARNING}, - .h_BaseObjectType = {CONSTANT_H_BASEOBJECTTYPE}, - .h_TypeType = {CONSTANT_H_TYPETYPE}, - .h_LongType = {CONSTANT_H_LONGTYPE}, - .h_UnicodeType = {CONSTANT_H_UNICODETYPE}, - .h_TupleType = {CONSTANT_H_TUPLETYPE}, - .h_ListType = {CONSTANT_H_LISTTYPE}, + /* h_None & co. are initialized by init_universal_ctx() */ .ctx_Module_Create = &ctx_Module_Create, .ctx_Dup = &ctx_Dup, .ctx_Close = &ctx_Close, diff --git a/hpy/universal/src/ctx_meth.c b/hpy/universal/src/ctx_meth.c index 42580aced..3e2bdd92b 100644 --- a/hpy/universal/src/ctx_meth.c +++ b/hpy/universal/src/ctx_meth.c @@ -31,26 +31,26 @@ ctx_CallRealFunctionFromTrampoline(HPyContext ctx, HPyFunc_Signature sig, return; } case HPyFunc_KEYWORDS: { - HPyFunc_keywords f = (HPyFunc_keywords)func; - _HPyFunc_args_KEYWORDS *a = (_HPyFunc_args_KEYWORDS*)args; - Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); - HPy h_args[nargs * sizeof(HPy)]; - for (Py_ssize_t i = 0; i < nargs; i++) { - h_args[i] = _py2h(PyTuple_GET_ITEM(a->args, i)); - } - a->result = _h2py(f(ctx, _py2h(a->self), h_args, nargs, _py2h(a->kw))); - return; + HPyFunc_keywords f = (HPyFunc_keywords)func; + _HPyFunc_args_KEYWORDS *a = (_HPyFunc_args_KEYWORDS*)args; + Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); + HPy h_args[nargs * sizeof(HPy)]; + for (Py_ssize_t i = 0; i < nargs; i++) { + h_args[i] = _py2h(PyTuple_GET_ITEM(a->args, i)); + } + a->result = _h2py(f(ctx, _py2h(a->self), h_args, nargs, _py2h(a->kw))); + return; } case HPyFunc_INITPROC: { - HPyFunc_initproc f = (HPyFunc_initproc)func; - _HPyFunc_args_INITPROC *a = (_HPyFunc_args_INITPROC*)args; - Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); - HPy h_args[nargs * sizeof(HPy)]; - for (Py_ssize_t i = 0; i < nargs; i++) { - h_args[i] = _py2h(PyTuple_GET_ITEM(a->args, i)); - } - a->result = f(ctx, _py2h(a->self), h_args, nargs, _py2h(a->kw)); - return; + HPyFunc_initproc f = (HPyFunc_initproc)func; + _HPyFunc_args_INITPROC *a = (_HPyFunc_args_INITPROC*)args; + Py_ssize_t nargs = PyTuple_GET_SIZE(a->args); + HPy h_args[nargs * sizeof(HPy)]; + for (Py_ssize_t i = 0; i < nargs; i++) { + h_args[i] = _py2h(PyTuple_GET_ITEM(a->args, i)); + } + a->result = f(ctx, _py2h(a->self), h_args, nargs, _py2h(a->kw)); + return; } #include "autogen_ctx_call.i" default: diff --git a/hpy/universal/src/ctx_misc.c b/hpy/universal/src/ctx_misc.c index a45dcfd2a..9afa98fc7 100644 --- a/hpy/universal/src/ctx_misc.c +++ b/hpy/universal/src/ctx_misc.c @@ -21,7 +21,8 @@ ctx_AsPyObject(HPyContext ctx, HPy h) HPyAPI_STORAGE void ctx_Close(HPyContext ctx, HPy h) { - _hclose(h); + PyObject *obj = _h2py(h); + Py_XDECREF(obj); } HPyAPI_STORAGE HPy diff --git a/hpy/universal/src/handles.c b/hpy/universal/src/handles.c deleted file mode 100644 index 79675da25..000000000 --- a/hpy/universal/src/handles.c +++ /dev/null @@ -1,192 +0,0 @@ -#include -#include -#include "hpy.h" -#include "handles.h" - - -#define hpy_assert(condition, ...) \ - do { \ - if (!(condition)) { \ - fprintf(stderr, "*** HPY HANDLES ERROR ***\n"); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - abort(); \ - } \ - } while (0) - - -/* XXX we should turn the fast-path of _py2h and _h2py into macros in api.h */ - -static PyObject **all_handles; -static Py_ssize_t h_num_allocated = 0; -static Py_ssize_t h_free_list = -1; -static Py_ssize_t h_free_list_2 = -1; -/* note: h_free_list_2 is only here for debugging. We can push freed - handles directly into h_free_list. But using two free lists makes - reuses occur later and in a less deterministic order. */ - -static void -allocate_more_handles(void) -{ - if (h_free_list_2 >= 0) { - h_free_list = h_free_list_2; - h_free_list_2 = -1; - return; - } - - Py_ssize_t base = (h_num_allocated < CONSTANT_H__TOTAL ? - CONSTANT_H__TOTAL : h_num_allocated); - Py_ssize_t i, allocate = (base / 2) * 3 + 32; - PyObject **new_handles = PyMem_Malloc(sizeof(PyObject *) * allocate); - memcpy(new_handles, all_handles, sizeof(PyObject *) * h_num_allocated); - - for (i = allocate - 1; i >= base; i--) { - new_handles[i] = (PyObject *)((h_free_list << 1) | 1); - h_free_list = i; - } - - if (h_num_allocated == 0) { - new_handles[CONSTANT_H_NULL] = NULL; - /* Constants */ - new_handles[CONSTANT_H_NONE] = Py_None; - new_handles[CONSTANT_H_TRUE] = Py_True; - new_handles[CONSTANT_H_FALSE] = Py_False; - /* Exceptions */ - new_handles[CONSTANT_H_BASEEXCEPTION] = PyExc_BaseException; - new_handles[CONSTANT_H_EXCEPTION] = PyExc_Exception; - new_handles[CONSTANT_H_STOPASYNCITERATION] = PyExc_StopAsyncIteration; - new_handles[CONSTANT_H_STOPITERATION] = PyExc_StopIteration; - new_handles[CONSTANT_H_GENERATOREXIT] = PyExc_GeneratorExit; - new_handles[CONSTANT_H_ARITHMETICERROR] = PyExc_ArithmeticError; - new_handles[CONSTANT_H_LOOKUPERROR] = PyExc_LookupError; - new_handles[CONSTANT_H_ASSERTIONERROR] = PyExc_AssertionError; - new_handles[CONSTANT_H_ATTRIBUTEERROR] = PyExc_AttributeError; - new_handles[CONSTANT_H_BUFFERERROR] = PyExc_BufferError; - new_handles[CONSTANT_H_EOFERROR] = PyExc_EOFError; - new_handles[CONSTANT_H_FLOATINGPOINTERROR] = PyExc_FloatingPointError; - new_handles[CONSTANT_H_OSERROR] = PyExc_OSError; - new_handles[CONSTANT_H_IMPORTERROR] = PyExc_ImportError; - new_handles[CONSTANT_H_MODULENOTFOUNDERROR] = PyExc_ModuleNotFoundError; - new_handles[CONSTANT_H_INDEXERROR] = PyExc_IndexError; - new_handles[CONSTANT_H_KEYERROR] = PyExc_KeyError; - new_handles[CONSTANT_H_KEYBOARDINTERRUPT] = PyExc_KeyboardInterrupt; - new_handles[CONSTANT_H_MEMORYERROR] = PyExc_MemoryError; - new_handles[CONSTANT_H_NAMEERROR] = PyExc_NameError; - new_handles[CONSTANT_H_OVERFLOWERROR] = PyExc_OverflowError; - new_handles[CONSTANT_H_RUNTIMEERROR] = PyExc_RuntimeError; - new_handles[CONSTANT_H_RECURSIONERROR] = PyExc_RecursionError; - new_handles[CONSTANT_H_NOTIMPLEMENTEDERROR] = PyExc_NotImplementedError; - new_handles[CONSTANT_H_SYNTAXERROR] = PyExc_SyntaxError; - new_handles[CONSTANT_H_INDENTATIONERROR] = PyExc_IndentationError; - new_handles[CONSTANT_H_TABERROR] = PyExc_TabError; - new_handles[CONSTANT_H_REFERENCEERROR] = PyExc_ReferenceError; - new_handles[CONSTANT_H_SYSTEMERROR] = PyExc_SystemError; - new_handles[CONSTANT_H_SYSTEMEXIT] = PyExc_SystemExit; - new_handles[CONSTANT_H_TYPEERROR] = PyExc_TypeError; - new_handles[CONSTANT_H_UNBOUNDLOCALERROR] = PyExc_UnboundLocalError; - new_handles[CONSTANT_H_UNICODEERROR] = PyExc_UnicodeError; - new_handles[CONSTANT_H_UNICODEENCODEERROR] = PyExc_UnicodeEncodeError; - new_handles[CONSTANT_H_UNICODEDECODEERROR] = PyExc_UnicodeDecodeError; - new_handles[CONSTANT_H_UNICODETRANSLATEERROR] = PyExc_UnicodeTranslateError; - new_handles[CONSTANT_H_VALUEERROR] = PyExc_ValueError; - new_handles[CONSTANT_H_ZERODIVISIONERROR] = PyExc_ZeroDivisionError; - new_handles[CONSTANT_H_BLOCKINGIOERROR] = PyExc_BlockingIOError; - new_handles[CONSTANT_H_BROKENPIPEERROR] = PyExc_BrokenPipeError; - new_handles[CONSTANT_H_CHILDPROCESSERROR] = PyExc_ChildProcessError; - new_handles[CONSTANT_H_CONNECTIONERROR] = PyExc_ConnectionError; - new_handles[CONSTANT_H_CONNECTIONABORTEDERROR] = PyExc_ConnectionAbortedError; - new_handles[CONSTANT_H_CONNECTIONREFUSEDERROR] = PyExc_ConnectionRefusedError; - new_handles[CONSTANT_H_CONNECTIONRESETERROR] = PyExc_ConnectionResetError; - new_handles[CONSTANT_H_FILEEXISTSERROR] = PyExc_FileExistsError; - new_handles[CONSTANT_H_FILENOTFOUNDERROR] = PyExc_FileNotFoundError; - new_handles[CONSTANT_H_INTERRUPTEDERROR] = PyExc_InterruptedError; - new_handles[CONSTANT_H_ISADIRECTORYERROR] = PyExc_IsADirectoryError; - new_handles[CONSTANT_H_NOTADIRECTORYERROR] = PyExc_NotADirectoryError; - new_handles[CONSTANT_H_PERMISSIONERROR] = PyExc_PermissionError; - new_handles[CONSTANT_H_PROCESSLOOKUPERROR] = PyExc_ProcessLookupError; - new_handles[CONSTANT_H_TIMEOUTERROR] = PyExc_TimeoutError; - /* Warnings */ - new_handles[CONSTANT_H_WARNING] = PyExc_Warning; - new_handles[CONSTANT_H_USERWARNING] = PyExc_UserWarning; - new_handles[CONSTANT_H_DEPRECATIONWARNING] = PyExc_DeprecationWarning; - new_handles[CONSTANT_H_PENDINGDEPRECATIONWARNING] = PyExc_PendingDeprecationWarning; - new_handles[CONSTANT_H_SYNTAXWARNING] = PyExc_SyntaxWarning; - new_handles[CONSTANT_H_RUNTIMEWARNING] = PyExc_RuntimeWarning; - new_handles[CONSTANT_H_FUTUREWARNING] = PyExc_FutureWarning; - new_handles[CONSTANT_H_IMPORTWARNING] = PyExc_ImportWarning; - new_handles[CONSTANT_H_UNICODEWARNING] = PyExc_UnicodeWarning; - new_handles[CONSTANT_H_BYTESWARNING] = PyExc_BytesWarning; - new_handles[CONSTANT_H_RESOURCEWARNING] = PyExc_ResourceWarning; - /* Types */ - new_handles[CONSTANT_H_BASEOBJECTTYPE] = (PyObject *)&PyBaseObject_Type; - new_handles[CONSTANT_H_TYPETYPE] = (PyObject *)&PyType_Type; - new_handles[CONSTANT_H_LONGTYPE] = (PyObject *)&PyLong_Type; - new_handles[CONSTANT_H_UNICODETYPE] = (PyObject *)&PyUnicode_Type; - new_handles[CONSTANT_H_TUPLETYPE] = (PyObject *)&PyTuple_Type; - new_handles[CONSTANT_H_LISTTYPE] = (PyObject *)&PyList_Type; - /* Check total */ - hpy_assert(CONSTANT_H__TOTAL == 74, - "update handles.c with the list of constants"); - } - - PyMem_Free(all_handles); - all_handles = new_handles; - h_num_allocated = allocate; -} - -HPy -_py2h(PyObject *obj) -{ - if (obj == NULL) { - // Return the existing copy of HPy_NULL and don't create a new - // handle. - return HPy_NULL; - } - if (h_free_list < 0) { - allocate_more_handles(); - } - Py_ssize_t i = h_free_list; - h_free_list = ((Py_ssize_t)all_handles[i]) >> 1; - all_handles[i] = obj; - return (HPy){i}; -} - -PyObject * -_h2py(HPy h) -{ - hpy_assert(h._i >= 0 && h._i < h_num_allocated, - "using an HPy containing garbage: _i = %p", (void *)h._i); - // If HPy_IsNull(h), the h._i = 0 and the line below returns the - // pointer attached to the 0th handle, i.e. NULL. - PyObject *result = all_handles[h._i]; - if (h._i == 0) { - hpy_assert(result == NULL, "handle number 0 doesn't contain NULL"); - return NULL; - } - hpy_assert((((Py_ssize_t)result) & 1) == 0, - "using an HPy that was freed already (or never allocated): _i = %p", - (void *)h._i); - hpy_assert(result != NULL, - "NULL PyObject unexpected in handle _i = %p", (void *)h._i); - hpy_assert(Py_REFCNT(result) > 0, - "bogus (freed?) PyObject found in handle _i = %p", (void *)h._i); - return result; -} - -void -_hclose(HPy h) -{ - Py_ssize_t i = h._i; - hpy_assert(i >= 0 && i < h_num_allocated, - "freeing an HPy containing garbage: _i = %p", (void *)i); - hpy_assert(i != 0, "freeing HPy_NULL is not allowed"); - PyObject *old = all_handles[i]; - hpy_assert((((Py_ssize_t)old) & 1) == 0, - "freeing an HPy that was freed already (or never allocated): _i = %p", - (void *)i); - hpy_assert(Py_REFCNT(old) > 0, - "bogus PyObject found while freeing handle _i = %p", (void *)h._i); - all_handles[i] = (PyObject *)((h_free_list_2 << 1) | 1); - h_free_list_2 = i; - Py_DECREF(old); -} diff --git a/hpy/universal/src/handles.h b/hpy/universal/src/handles.h index b9fb0f9ad..cb722e9bc 100644 --- a/hpy/universal/src/handles.h +++ b/hpy/universal/src/handles.h @@ -2,93 +2,23 @@ #define HPY_HANDLES_H #include +#include "hpy.h" -// this should maybe autogenerated from public_api.h -enum { - CONSTANT_H_NULL = 0, - /* Constants */ - CONSTANT_H_NONE, - CONSTANT_H_TRUE, - CONSTANT_H_FALSE, - /* Exceptions */ - CONSTANT_H_BASEEXCEPTION, - CONSTANT_H_EXCEPTION, - CONSTANT_H_STOPASYNCITERATION, - CONSTANT_H_STOPITERATION, - CONSTANT_H_GENERATOREXIT, - CONSTANT_H_ARITHMETICERROR, - CONSTANT_H_LOOKUPERROR, - CONSTANT_H_ASSERTIONERROR, - CONSTANT_H_ATTRIBUTEERROR, - CONSTANT_H_BUFFERERROR, - CONSTANT_H_EOFERROR, - CONSTANT_H_FLOATINGPOINTERROR, - CONSTANT_H_OSERROR, - CONSTANT_H_IMPORTERROR, - CONSTANT_H_MODULENOTFOUNDERROR, - CONSTANT_H_INDEXERROR, - CONSTANT_H_KEYERROR, - CONSTANT_H_KEYBOARDINTERRUPT, - CONSTANT_H_MEMORYERROR, - CONSTANT_H_NAMEERROR, - CONSTANT_H_OVERFLOWERROR, - CONSTANT_H_RUNTIMEERROR, - CONSTANT_H_RECURSIONERROR, - CONSTANT_H_NOTIMPLEMENTEDERROR, - CONSTANT_H_SYNTAXERROR, - CONSTANT_H_INDENTATIONERROR, - CONSTANT_H_TABERROR, - CONSTANT_H_REFERENCEERROR, - CONSTANT_H_SYSTEMERROR, - CONSTANT_H_SYSTEMEXIT, - CONSTANT_H_TYPEERROR, - CONSTANT_H_UNBOUNDLOCALERROR, - CONSTANT_H_UNICODEERROR, - CONSTANT_H_UNICODEENCODEERROR, - CONSTANT_H_UNICODEDECODEERROR, - CONSTANT_H_UNICODETRANSLATEERROR, - CONSTANT_H_VALUEERROR, - CONSTANT_H_ZERODIVISIONERROR, - CONSTANT_H_BLOCKINGIOERROR, - CONSTANT_H_BROKENPIPEERROR, - CONSTANT_H_CHILDPROCESSERROR, - CONSTANT_H_CONNECTIONERROR, - CONSTANT_H_CONNECTIONABORTEDERROR, - CONSTANT_H_CONNECTIONREFUSEDERROR, - CONSTANT_H_CONNECTIONRESETERROR, - CONSTANT_H_FILEEXISTSERROR, - CONSTANT_H_FILENOTFOUNDERROR, - CONSTANT_H_INTERRUPTEDERROR, - CONSTANT_H_ISADIRECTORYERROR, - CONSTANT_H_NOTADIRECTORYERROR, - CONSTANT_H_PERMISSIONERROR, - CONSTANT_H_PROCESSLOOKUPERROR, - CONSTANT_H_TIMEOUTERROR, - /* Warnings */ - CONSTANT_H_WARNING, - CONSTANT_H_USERWARNING, - CONSTANT_H_DEPRECATIONWARNING, - CONSTANT_H_PENDINGDEPRECATIONWARNING, - CONSTANT_H_SYNTAXWARNING, - CONSTANT_H_RUNTIMEWARNING, - CONSTANT_H_FUTUREWARNING, - CONSTANT_H_IMPORTWARNING, - CONSTANT_H_UNICODEWARNING, - CONSTANT_H_BYTESWARNING, - CONSTANT_H_RESOURCEWARNING, - /* Types */ - CONSTANT_H_BASEOBJECTTYPE, - CONSTANT_H_TYPETYPE, - CONSTANT_H_LONGTYPE, - CONSTANT_H_UNICODETYPE, - CONSTANT_H_TUPLETYPE, - CONSTANT_H_LISTTYPE, - /* Total */ - CONSTANT_H__TOTAL, -}; +// The main reason for +1/-1 is to make sure that if people casts HPy to +// PyObject* directly, things explode. Moreover, with this we can easily +// distinguish normal and debug handles in gdb, by only looking at the last +// bit. -HPy _py2h(PyObject *); -PyObject *_h2py(HPy); -void _hclose(HPy); +static inline HPy _py2h(PyObject *obj) { + if (obj == NULL) + return HPy_NULL; + return (HPy){(HPy_ssize_t)obj + 1}; +} + +static inline PyObject *_h2py(HPy h) { + if HPy_IsNull(h) + return NULL; + return (PyObject *)(h._i - 1); +} #endif /* HPY_HANDLES_H */ diff --git a/hpy/universal/src/hpymodule.c b/hpy/universal/src/hpymodule.c index 35892a80e..76ce96d18 100644 --- a/hpy/universal/src/hpymodule.c +++ b/hpy/universal/src/hpymodule.c @@ -11,6 +11,7 @@ #include "api.h" #include "handles.h" #include "common/version.h" +#include "hpy_debug.h" #ifdef PYPY_VERSION # error "Cannot build hpy.univeral on top of PyPy. PyPy comes with its own version of it" @@ -26,6 +27,14 @@ static PyObject *set_debug(PyObject *self, PyObject *args) static const char *prefix = "HPyInit"; +static HPyContext get_context(int debug) +{ + if (debug) + return hpy_debug_get_ctx(&g_universal_ctx); + else + return &g_universal_ctx; +} + static PyObject * get_encoded_name(PyObject *name) { PyObject *tmp; @@ -69,17 +78,11 @@ get_encoded_name(PyObject *name) { return NULL; } - -static PyObject *load_from_spec(PyObject *self, PyObject *spec) +static PyObject *do_load(PyObject *name_unicode, PyObject *path, int debug) { - PyObject *name_unicode, *name; - PyObject *path = NULL; + PyObject *name = NULL; PyObject *pathbytes = NULL; - name_unicode = PyObject_GetAttrString(spec, "name"); - if (name_unicode == NULL) { - return NULL; - } name = get_encoded_name(name_unicode); if (name == NULL) { goto error; @@ -89,9 +92,6 @@ static PyObject *load_from_spec(PyObject *self, PyObject *spec) PyOS_snprintf(init_name, sizeof(init_name), "%.20s_%.200s", prefix, shortname); - path = PyObject_GetAttrString(spec, "origin"); - if (path == NULL) - goto error; pathbytes = PyUnicode_EncodeFSDefault(path); if (pathbytes == NULL) goto error; @@ -115,25 +115,37 @@ static PyObject *load_from_spec(PyObject *self, PyObject *spec) goto error; } - HPy mod = ((InitFuncPtr)initfn)(&global_ctx); - if (HPy_IsNull(mod)) + HPyContext ctx = get_context(debug); + if (ctx == NULL) + goto error; + HPy h_mod = ((InitFuncPtr)initfn)(ctx); + if (HPy_IsNull(h_mod)) goto error; - PyObject *py_mod = _h2py(mod); - // XXX close the handle + PyObject *py_mod = HPy_AsPyObject(ctx, h_mod); + HPy_Close(ctx, h_mod); - Py_DECREF(name_unicode); Py_XDECREF(name); - Py_XDECREF(path); Py_XDECREF(pathbytes); return py_mod; error: - Py_DECREF(name_unicode); Py_XDECREF(name); - Py_XDECREF(path); Py_XDECREF(pathbytes); return NULL; } +static PyObject *load(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = {"name", "path", "debug", NULL}; + PyObject *name_unicode; + PyObject *path; + int debug = 0; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|p", kwlist, + &name_unicode, &path, &debug)) { + return NULL; + } + return do_load(name_unicode, path, debug); +} + static PyObject *get_version(PyObject *self, PyObject *ignored) { return Py_BuildValue("ss", HPY_VERSION, HPY_GIT_REVISION); @@ -141,11 +153,16 @@ static PyObject *get_version(PyObject *self, PyObject *ignored) static PyMethodDef HPyMethods[] = { {"set_debug", (PyCFunction)set_debug, METH_O, "TODO"}, - {"load_from_spec", (PyCFunction)load_from_spec, METH_O, "Load a .hpy.so"}, + {"load", (PyCFunction)load, METH_VARARGS | METH_KEYWORDS, "Load a .hpy.so"}, {"get_version", (PyCFunction)get_version, METH_NOARGS, "Return a tuple ('version', 'git revision')"}, {NULL, NULL, 0, NULL} }; +static int exec_module(PyObject *mod); +static PyModuleDef_Slot hpymodule_slots[] = { + {Py_mod_exec, exec_module}, + {0, NULL}, +}; static struct PyModuleDef hpydef = { PyModuleDef_HEAD_INIT, @@ -153,11 +170,119 @@ static struct PyModuleDef hpydef = { .m_doc = "HPy universal runtime for CPython", .m_size = 0, .m_methods = HPyMethods, + .m_slots = hpymodule_slots, }; +// module initialization function +int exec_module(PyObject* mod) { + HPyContext ctx = &g_universal_ctx; + HPy h_debug_mod = HPyInit__debug(ctx); + if (HPy_IsNull(h_debug_mod)) + return -1; + PyObject *_debug_mod = HPy_AsPyObject(ctx, h_debug_mod); + HPy_Close(ctx, h_debug_mod); + + if (PyModule_AddObject(mod, "_debug", _debug_mod) < 0) + return -1; + + return 0; +} + +static void init_universal_ctx(HPyContext ctx) +{ + if (!HPy_IsNull(ctx->h_None)) + // already initialized + return; + + // XXX this code is basically the same as found in cpython/hpy.h. We + // should probably share and/or autogenerate both versions + /* Constants */ + ctx->h_None = _py2h(Py_None); + ctx->h_True = _py2h(Py_True); + ctx->h_False = _py2h(Py_False); + ctx->h_NotImplemented = _py2h(Py_NotImplemented); + ctx->h_Ellipsis = _py2h(Py_Ellipsis); + /* Exceptions */ + ctx->h_BaseException = _py2h(PyExc_BaseException); + ctx->h_Exception = _py2h(PyExc_Exception); + ctx->h_StopAsyncIteration = _py2h(PyExc_StopAsyncIteration); + ctx->h_StopIteration = _py2h(PyExc_StopIteration); + ctx->h_GeneratorExit = _py2h(PyExc_GeneratorExit); + ctx->h_ArithmeticError = _py2h(PyExc_ArithmeticError); + ctx->h_LookupError = _py2h(PyExc_LookupError); + ctx->h_AssertionError = _py2h(PyExc_AssertionError); + ctx->h_AttributeError = _py2h(PyExc_AttributeError); + ctx->h_BufferError = _py2h(PyExc_BufferError); + ctx->h_EOFError = _py2h(PyExc_EOFError); + ctx->h_FloatingPointError = _py2h(PyExc_FloatingPointError); + ctx->h_OSError = _py2h(PyExc_OSError); + ctx->h_ImportError = _py2h(PyExc_ImportError); + ctx->h_ModuleNotFoundError = _py2h(PyExc_ModuleNotFoundError); + ctx->h_IndexError = _py2h(PyExc_IndexError); + ctx->h_KeyError = _py2h(PyExc_KeyError); + ctx->h_KeyboardInterrupt = _py2h(PyExc_KeyboardInterrupt); + ctx->h_MemoryError = _py2h(PyExc_MemoryError); + ctx->h_NameError = _py2h(PyExc_NameError); + ctx->h_OverflowError = _py2h(PyExc_OverflowError); + ctx->h_RuntimeError = _py2h(PyExc_RuntimeError); + ctx->h_RecursionError = _py2h(PyExc_RecursionError); + ctx->h_NotImplementedError = _py2h(PyExc_NotImplementedError); + ctx->h_SyntaxError = _py2h(PyExc_SyntaxError); + ctx->h_IndentationError = _py2h(PyExc_IndentationError); + ctx->h_TabError = _py2h(PyExc_TabError); + ctx->h_ReferenceError = _py2h(PyExc_ReferenceError); + ctx->h_SystemError = _py2h(PyExc_SystemError); + ctx->h_SystemExit = _py2h(PyExc_SystemExit); + ctx->h_TypeError = _py2h(PyExc_TypeError); + ctx->h_UnboundLocalError = _py2h(PyExc_UnboundLocalError); + ctx->h_UnicodeError = _py2h(PyExc_UnicodeError); + ctx->h_UnicodeEncodeError = _py2h(PyExc_UnicodeEncodeError); + ctx->h_UnicodeDecodeError = _py2h(PyExc_UnicodeDecodeError); + ctx->h_UnicodeTranslateError = _py2h(PyExc_UnicodeTranslateError); + ctx->h_ValueError = _py2h(PyExc_ValueError); + ctx->h_ZeroDivisionError = _py2h(PyExc_ZeroDivisionError); + ctx->h_BlockingIOError = _py2h(PyExc_BlockingIOError); + ctx->h_BrokenPipeError = _py2h(PyExc_BrokenPipeError); + ctx->h_ChildProcessError = _py2h(PyExc_ChildProcessError); + ctx->h_ConnectionError = _py2h(PyExc_ConnectionError); + ctx->h_ConnectionAbortedError = _py2h(PyExc_ConnectionAbortedError); + ctx->h_ConnectionRefusedError = _py2h(PyExc_ConnectionRefusedError); + ctx->h_ConnectionResetError = _py2h(PyExc_ConnectionResetError); + ctx->h_FileExistsError = _py2h(PyExc_FileExistsError); + ctx->h_FileNotFoundError = _py2h(PyExc_FileNotFoundError); + ctx->h_InterruptedError = _py2h(PyExc_InterruptedError); + ctx->h_IsADirectoryError = _py2h(PyExc_IsADirectoryError); + ctx->h_NotADirectoryError = _py2h(PyExc_NotADirectoryError); + ctx->h_PermissionError = _py2h(PyExc_PermissionError); + ctx->h_ProcessLookupError = _py2h(PyExc_ProcessLookupError); + ctx->h_TimeoutError = _py2h(PyExc_TimeoutError); + /* Warnings */ + ctx->h_Warning = _py2h(PyExc_Warning); + ctx->h_UserWarning = _py2h(PyExc_UserWarning); + ctx->h_DeprecationWarning = _py2h(PyExc_DeprecationWarning); + ctx->h_PendingDeprecationWarning = _py2h(PyExc_PendingDeprecationWarning); + ctx->h_SyntaxWarning = _py2h(PyExc_SyntaxWarning); + ctx->h_RuntimeWarning = _py2h(PyExc_RuntimeWarning); + ctx->h_FutureWarning = _py2h(PyExc_FutureWarning); + ctx->h_ImportWarning = _py2h(PyExc_ImportWarning); + ctx->h_UnicodeWarning = _py2h(PyExc_UnicodeWarning); + ctx->h_BytesWarning = _py2h(PyExc_BytesWarning); + ctx->h_ResourceWarning = _py2h(PyExc_ResourceWarning); + /* Types */ + ctx->h_BaseObjectType = _py2h((PyObject *)&PyBaseObject_Type); + ctx->h_TypeType = _py2h((PyObject *)&PyType_Type); + ctx->h_LongType = _py2h((PyObject *)&PyLong_Type); + ctx->h_UnicodeType = _py2h((PyObject *)&PyUnicode_Type); + ctx->h_TupleType = _py2h((PyObject *)&PyTuple_Type); + ctx->h_ListType = _py2h((PyObject *)&PyList_Type); +} + + PyMODINIT_FUNC PyInit_universal(void) { - return PyModuleDef_Init(&hpydef); + init_universal_ctx(&g_universal_ctx); + PyObject *mod = PyModuleDef_Init(&hpydef); + return mod; } diff --git a/setup.py b/setup.py index 1b0006c2b..66a81270f 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,8 @@ if 'HPY_DEBUG' in os.environ: # -fkeep-inline-functions is needed to make sure that the stubs for HPy_* # functions are available to call inside GDB - EXTRA_COMPILE_ARGS = ['-g', '-O0', '-fkeep-inline-functions'] + EXTRA_COMPILE_ARGS = ['-g', '-O0', '-UNDEBUG', + '-fkeep-inline-functions'] else: EXTRA_COMPILE_ARGS = [] @@ -47,7 +48,6 @@ def get_scm_config(): EXT_MODULES += [ Extension('hpy.universal', ['hpy/universal/src/hpymodule.c', - 'hpy/universal/src/handles.c', 'hpy/universal/src/ctx.c', 'hpy/universal/src/ctx_meth.c', 'hpy/universal/src/ctx_misc.c', @@ -60,10 +60,16 @@ def get_scm_config(): 'hpy/devel/src/runtime/ctx_listbuilder.c', 'hpy/devel/src/runtime/ctx_tuple.c', 'hpy/devel/src/runtime/ctx_tuplebuilder.c', + 'hpy/debug/src/debug_ctx.c', + 'hpy/debug/src/debug_ctx_cpython.c', + 'hpy/debug/src/debug_handles.c', + 'hpy/debug/src/_debugmod.c', + 'hpy/debug/src/autogen_debug_wrappers.c', ], include_dirs=[ 'hpy/devel/include', 'hpy/universal/src', + 'hpy/debug/src/include', ], extra_compile_args=[ '-DHPY_UNIVERSAL_ABI', diff --git a/test/conftest.py b/test/conftest.py index b601413f7..2581619aa 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -11,7 +11,7 @@ def hpy_devel(request): from hpy.devel import HPyDevel return HPyDevel() -@pytest.fixture(params=['cpython', 'universal']) +@pytest.fixture(params=['cpython', 'universal', 'debug']) def hpy_abi(request): return request.param diff --git a/test/support.py b/test/support.py index fe0a91b23..3594796c6 100644 --- a/test/support.py +++ b/test/support.py @@ -190,43 +190,64 @@ def compile_module(self, ExtensionTemplate, main_src, name, extra_sources): extra_compile_args=compile_args, extra_link_args=link_args) + hpy_abi = self.hpy_abi + if hpy_abi == 'debug': + # there is no compile-time difference between universal and debug + # extensions. The only difference happens at load time + hpy_abi = 'universal' so_filename = c_compile(str(self.tmpdir), ext, hpy_devel=self.hpy_devel, - hpy_abi=self.hpy_abi, + hpy_abi=hpy_abi, compiler_verbose=self.compiler_verbose) return so_filename def make_module(self, ExtensionTemplate, main_src, name, extra_sources): """ Compile & load a module. This is NOT a proper import: e.g. - the module is not put into sys.modules + the module is not put into sys.modules. + + We don't want to unnecessarily modify the global state inside tests: + if you are writing a test which needs a proper import, you should not + use make_module but explicitly use compile_module and import it + manually as requied by your test. """ - mod_filename = self.compile_module( + so_filename = self.compile_module( ExtensionTemplate, main_src, name, extra_sources) - return self.load_module(name, mod_filename) + if self.hpy_abi == 'universal': + return self.load_universal_module(name, so_filename, debug=False) + elif self.hpy_abi == 'debug': + return self.load_universal_module(name, so_filename, debug=True) + elif self.hpy_abi == 'cpython': + return self.load_cpython_module(name, so_filename) + else: + assert False - def load_module(self, name, mod_filename): - # It is important to do the imports only here, because this file will - # be imported also by PyPy tests which runs on Python2 - import importlib + def load_universal_module(self, name, so_filename, debug): + assert self.hpy_abi in ('universal', 'debug') import sys - import os - if name in sys.modules: - raise ValueError( - "Test module {!r} already present in sys.modules".format(name)) - importlib.invalidate_caches() - mod_dir = os.path.dirname(mod_filename) - sys.path.insert(0, mod_dir) + import hpy.universal + assert name not in sys.modules + mod = hpy.universal.load(name, so_filename, debug=debug) + mod.__file__ = so_filename + return mod + + def load_cpython_module(self, name, so_filename): + assert self.hpy_abi == 'cpython' + # we've got a normal CPython module compiled with the CPython API/ABI, + # let's load it normally. It is important to do the imports only here, + # because this file will be imported also by PyPy tests which runs on + # Python2 + import importlib.util + import sys + assert name not in sys.modules + spec = importlib.util.spec_from_file_location(name, so_filename) try: - module = importlib.import_module(name) - assert sys.modules[name] is module + # module_from_spec adds the module to sys.modules + module = importlib.util.module_from_spec(spec) finally: - # assert that the module import didn't change the sys.path entry - # that was added above, then remove the entry. - assert sys.path[0] == mod_dir - del sys.path[0] if name in sys.modules: del sys.modules[name] + spec.loader.exec_module(module) return module @@ -320,11 +341,11 @@ def _build(tmpdir, ext, hpy_devel, hpy_abi, compiler_verbose=0, debug=None): dist.run_command('build_ext') cmd_obj = dist.get_command_obj('build_ext') outputs = cmd_obj.get_outputs() - if hpy_abi == "cpython": - [mod_filename] = [x for x in outputs if not x.endswith(".py")] - else: - [mod_filename] = [x for x in outputs if x.endswith(".py")] + sonames = [x for x in outputs if + not x.endswith(".py") and not x.endswith(".pyc")] + assert len(sonames) == 1, 'build_ext is not supposed to return multiple DLLs' + soname = sonames[0] finally: distutils.log.set_threshold(old_level) - return mod_filename + return soname diff --git a/test/test_00_basic.py b/test/test_00_basic.py index 1b639e50b..786673421 100644 --- a/test/test_00_basic.py +++ b/test/test_00_basic.py @@ -164,6 +164,21 @@ def test_exception(self): mod.f(20) assert str(exc.value) == 'hello world' + def test_varargs(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_VARARGS) + static HPy f_impl(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs) + { + long a, b; + if (!HPyArg_Parse(ctx, NULL, args, nargs, "ll", &a, &b)) + return HPy_NULL; + return HPyLong_FromLong(ctx, 10*a + b); + } + @EXPORT(f) + @INIT + """) + assert mod.f(4, 5) == 45 + def test_builtin_handles(self): mod = self.make_module(""" HPyDef_METH(f, "f", f_impl, HPyFunc_O) @@ -185,6 +200,8 @@ def test_builtin_handles(self): case 11: h = ctx->h_UnicodeType; break; case 12: h = ctx->h_TupleType; break; case 13: h = ctx->h_ListType; break; + case 14: h = ctx->h_NotImplemented; break; + case 15: h = ctx->h_Ellipsis; break; default: HPyErr_SetString(ctx, ctx->h_ValueError, "invalid choice"); return HPy_NULL; @@ -196,7 +213,7 @@ def test_builtin_handles(self): """) builtin_objs = ( '', None, False, True, ValueError, TypeError, IndexError, - SystemError, object, type, int, str, tuple, list, + SystemError, object, type, int, str, tuple, list, NotImplemented, Ellipsis, ) for i, obj in enumerate(builtin_objs): if i == 0: @@ -376,3 +393,26 @@ def test_hash(self): """) x = object() assert mod.f(x) == hash(x) + + def test_ctx_name(self, hpy_abi): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) + static HPy f_impl(HPyContext ctx, HPy self) + { + return HPyUnicode_FromString(ctx, ctx->name); + } + + @EXPORT(f) + @INIT + """) + ctx_name = mod.f() + if hpy_abi == 'cpython': + assert ctx_name == 'HPy CPython ABI' + elif hpy_abi == 'universal': + # this can be "HPy Universal ABI (CPython backend)" or + # "... (PyPy backend)", etc. + assert ctx_name.startswith('HPy Universal ABI') + elif hpy_abi == 'debug': + assert ctx_name.startswith('HPy Debug Mode ABI') + else: + assert False, 'unexpected hpy_abi: %s' % hpy_abi diff --git a/test/test_debug.py b/test/test_debug.py new file mode 100644 index 000000000..630077034 --- /dev/null +++ b/test/test_debug.py @@ -0,0 +1,153 @@ +import pytest +from .support import HPyTest + + +class TestDebug(HPyTest): + + # these tests are run only with hpy_abi=='debug'. We will probably need to + # tweak the approach to make it working with PyPy's apptests + @pytest.fixture(params=['debug']) + def hpy_abi(self, request): + return request.param + + def test_get_open_handles(self): + from hpy.universal import _debug + mod = self.make_module(""" + HPyDef_METH(leak, "leak", leak_impl, HPyFunc_O) + static HPy leak_impl(HPyContext ctx, HPy self, HPy arg) + { + HPy_Dup(ctx, arg); // leak! + return HPy_Dup(ctx, ctx->h_None); + } + @EXPORT(leak) + @INIT + """) + gen1 = _debug.new_generation() + mod.leak('hello') + mod.leak('world') + gen2 = _debug.new_generation() + mod.leak('a younger leak') + leaks1 = _debug.get_open_handles(gen1) + leaks2 = _debug.get_open_handles(gen2) + leaks1 = [dh.obj for dh in leaks1] + leaks2 = [dh.obj for dh in leaks2] + assert leaks1 == ['a younger leak', 'world', 'hello'] + assert leaks2 == ['a younger leak'] + + def test_DebugHandle_id(self): + from hpy.universal import _debug + mod = self.make_module(""" + HPyDef_METH(leak, "leak", leak_impl, HPyFunc_O) + static HPy leak_impl(HPyContext ctx, HPy self, HPy arg) + { + HPy_Dup(ctx, arg); // leak! + return HPy_Dup(ctx, ctx->h_None); + } + @EXPORT(leak) + @INIT + """) + gen = _debug.new_generation() + mod.leak('a') + mod.leak('b') + b1, a1 = _debug.get_open_handles(gen) + b2, a2 = _debug.get_open_handles(gen) + assert a1.obj == a2.obj == 'a' + assert b1.obj == b2.obj == 'b' + # + assert a1 is not a2 + assert b1 is not b2 + # + assert a1.id == a2.id + assert b1.id == b2.id + assert a1.id != b1.id + + def test_DebugHandle_compare(self): + import pytest + from hpy.universal import _debug + mod = self.make_module(""" + HPyDef_METH(leak, "leak", leak_impl, HPyFunc_O) + static HPy leak_impl(HPyContext ctx, HPy self, HPy arg) + { + HPy_Dup(ctx, arg); // leak! + return HPy_Dup(ctx, ctx->h_None); + } + @EXPORT(leak) + @INIT + """) + gen = _debug.new_generation() + mod.leak('a') + mod.leak('a') + a2, a1 = _debug.get_open_handles(gen) + assert a1 != a2 # same underlying object, but different DebugHandle + # + a2_new, a1_new = _debug.get_open_handles(gen) + assert a1 is not a1_new # different objects... + assert a2 is not a2_new + assert a1 == a1_new # ...but same DebugHandle + assert a2 == a2_new + # + with pytest.raises(TypeError): + a1 < a2 + with pytest.raises(TypeError): + a1 <= a2 + with pytest.raises(TypeError): + a1 > a2 + with pytest.raises(TypeError): + a1 >= a2 + + assert not a1 == 'hello' + assert a1 != 'hello' + with pytest.raises(TypeError): + a1 < 'hello' + + def test_DebugHandle_repr(self): + import pytest + from hpy.universal import _debug + mod = self.make_module(""" + HPyDef_METH(leak, "leak", leak_impl, HPyFunc_O) + static HPy leak_impl(HPyContext ctx, HPy self, HPy arg) + { + HPy_Dup(ctx, arg); // leak! + return HPy_Dup(ctx, ctx->h_None); + } + @EXPORT(leak) + @INIT + """) + gen = _debug.new_generation() + mod.leak('hello') + h_hello, = _debug.get_open_handles(gen) + assert repr(h_hello) == "" % h_hello.id + + def test_LeakDetector(self): + import pytest + from hpy.debug import LeakDetector, HPyLeak + mod = self.make_module(""" + HPyDef_METH(leak, "leak", leak_impl, HPyFunc_O) + static HPy leak_impl(HPyContext ctx, HPy self, HPy arg) + { + HPy_Dup(ctx, arg); // leak! + return HPy_Dup(ctx, ctx->h_None); + } + @EXPORT(leak) + @INIT + """) + ld = LeakDetector() + ld.start() + mod.leak('hello') + mod.leak('world') + with pytest.raises(HPyLeak) as exc: + ld.stop() + assert str(exc.value).startswith('2 handles have not been closed properly:') + # + with pytest.raises(HPyLeak) as exc: + with LeakDetector(): + mod.leak('foo') + mod.leak('bar') + mod.leak('baz') + msg = str(exc.value) + assert msg.startswith('3 handles have not been closed properly:') + assert 'foo' in msg + assert 'bar' in msg + assert 'baz' in msg + assert 'hello' not in msg + assert 'world' not in msg diff --git a/test/test_importing.py b/test/test_importing.py index 94de0b11d..7630fa541 100644 --- a/test/test_importing.py +++ b/test/test_importing.py @@ -3,6 +3,28 @@ class TestImporting(HPyTest): + def full_import(self, name, mod_filename): + import importlib + import sys + import os + if name in sys.modules: + raise ValueError( + "Test module {!r} already present in sys.modules".format(name)) + importlib.invalidate_caches() + mod_dir = os.path.dirname(mod_filename) + sys.path.insert(0, mod_dir) + try: + module = importlib.import_module(name) + assert sys.modules[name] is module + finally: + # assert that the module import didn't change the sys.path entry + # that was added above, then remove the entry. + assert sys.path[0] == mod_dir + del sys.path[0] + if name in sys.modules: + del sys.modules[name] + return module + def test_importing_attributes(self): import pytest if not self.supports_ordinary_make_module_imports(): @@ -10,6 +32,7 @@ def test_importing_attributes(self): mod = self.make_module(""" @INIT """, name='mytest') + mod = self.full_import(mod.__name__, mod.__file__) assert mod.__name__ == 'mytest' assert mod.__package__ == '' assert mod.__doc__ == 'some test for hpy'