From deb835e17429c0143b0084b31ff33e59e5b4910a Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 7 Aug 2020 13:06:48 +0200 Subject: [PATCH 1/6] forgot to add this file earlier --- test/test_hpyerr.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/test_hpyerr.py diff --git a/test/test_hpyerr.py b/test/test_hpyerr.py new file mode 100644 index 000000000..382b516cc --- /dev/null +++ b/test/test_hpyerr.py @@ -0,0 +1,17 @@ +from .support import HPyTest + +class TestErr(HPyTest): + + def test_NoMemory(self): + import pytest + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) + static HPy f_impl(HPyContext ctx, HPy self) + { + return HPyErr_NoMemory(ctx); + } + @EXPORT(f) + @INIT + """) + with pytest.raises(MemoryError): + mod.f() From 7c8a04df1029ee9047f68e667783f28ef9dfcafc Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 7 Aug 2020 13:39:03 +0200 Subject: [PATCH 2/6] (antocuni, arigo): we need to special case tp_init, because it has a 'call-like' signature --- .../include/common/autogen_hpyfunc_declare.h | 4 +- .../cpython/autogen_hpyfunc_trampolines.h | 5 -- .../include/cpython/hpyfunc_trampolines.h | 12 +++++ .../universal/autogen_hpyfunc_trampolines.h | 16 ------ .../include/universal/hpyfunc_trampolines.h | 17 +++++++ hpy/tools/autogen/hpyfunc.py | 7 +-- hpy/tools/autogen/public_api.h | 3 +- hpy/universal/src/autogen_ctx_call.i | 6 --- hpy/universal/src/ctx_meth.c | 11 ++++ test/test_hpytype.py | 50 +++++++++++++++++++ 10 files changed, 98 insertions(+), 33 deletions(-) diff --git a/hpy/devel/include/common/autogen_hpyfunc_declare.h b/hpy/devel/include/common/autogen_hpyfunc_declare.h index 7c00783d4..bfc96042d 100644 --- a/hpy/devel/include/common/autogen_hpyfunc_declare.h +++ b/hpy/devel/include/common/autogen_hpyfunc_declare.h @@ -35,7 +35,7 @@ #define _HPyFunc_DECLARE_HPyFunc_ITERNEXTFUNC(SYM) static HPy SYM(HPyContext ctx, HPy) #define _HPyFunc_DECLARE_HPyFunc_DESCRGETFUNC(SYM) static HPy SYM(HPyContext ctx, HPy, HPy, HPy) #define _HPyFunc_DECLARE_HPyFunc_DESCRSETFUNC(SYM) static int SYM(HPyContext ctx, HPy, HPy, HPy) -#define _HPyFunc_DECLARE_HPyFunc_INITPROC(SYM) static int SYM(HPyContext ctx, HPy, HPy, HPy) +#define _HPyFunc_DECLARE_HPyFunc_INITPROC(SYM) static int SYM(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, HPy kw) typedef HPy (*HPyFunc_noargs)(HPyContext ctx, HPy self); typedef HPy (*HPyFunc_o)(HPyContext ctx, HPy self, HPy arg); @@ -64,4 +64,4 @@ typedef HPy (*HPyFunc_getiterfunc)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_iternextfunc)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_descrgetfunc)(HPyContext ctx, HPy, HPy, HPy); typedef int (*HPyFunc_descrsetfunc)(HPyContext ctx, HPy, HPy, HPy); -typedef int (*HPyFunc_initproc)(HPyContext ctx, HPy, HPy, HPy); +typedef int (*HPyFunc_initproc)(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, HPy kw); diff --git a/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h b/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h index 3333e730d..f38f8bbd4 100644 --- a/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h +++ b/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h @@ -123,8 +123,3 @@ { \ return (IMPL(_HPyGetContext(), _py2h(arg0), _py2h(arg1), _py2h(arg2))); \ } -#define _HPyFunc_TRAMPOLINE_HPyFunc_INITPROC(SYM, IMPL) \ - static int SYM(cpy_PyObject *arg0, cpy_PyObject *arg1, cpy_PyObject *arg2) \ - { \ - return (IMPL(_HPyGetContext(), _py2h(arg0), _py2h(arg1), _py2h(arg2))); \ - } diff --git a/hpy/devel/include/cpython/hpyfunc_trampolines.h b/hpy/devel/include/cpython/hpyfunc_trampolines.h index d8d3626ba..44b20711c 100644 --- a/hpy/devel/include/cpython/hpyfunc_trampolines.h +++ b/hpy/devel/include/cpython/hpyfunc_trampolines.h @@ -40,4 +40,16 @@ items, nargs, _py2h(kw))); \ } +#define _HPyFunc_TRAMPOLINE_HPyFunc_INITPROC(SYM, IMPL) \ + static int \ + SYM(PyObject *self, PyObject *args, PyObject *kw) \ + { \ + /* get the tuple elements as an array of "PyObject *", which */ \ + /* is equivalent to an array of "HPy" with enough casting... */ \ + HPy *items = (HPy *)&PyTuple_GET_ITEM(args, 0); \ + Py_ssize_t nargs = PyTuple_GET_SIZE(args); \ + return IMPL(_HPyGetContext(), _py2h(self), \ + items, nargs, _py2h(kw)); \ + } + #endif // HPY_CPYTHON_HPYFUNC_TRAMPOLINES_H diff --git a/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h b/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h index dc419b7f3..1016229a6 100644 --- a/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h +++ b/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h @@ -353,19 +353,3 @@ typedef struct { return a.result; \ } -typedef struct { - cpy_PyObject *arg0; - cpy_PyObject *arg1; - cpy_PyObject *arg2; - int result; -} _HPyFunc_args_INITPROC; - -#define _HPyFunc_TRAMPOLINE_HPyFunc_INITPROC(SYM, IMPL) \ - static int SYM(cpy_PyObject *arg0, cpy_PyObject *arg1, cpy_PyObject *arg2) \ - { \ - _HPyFunc_args_INITPROC a = { arg0, arg1, arg2 }; \ - _HPy_CallRealFunctionFromTrampoline( \ - _ctx_for_trampolines, HPyFunc_INITPROC, IMPL, &a); \ - return a.result; \ - } - diff --git a/hpy/devel/include/universal/hpyfunc_trampolines.h b/hpy/devel/include/universal/hpyfunc_trampolines.h index 5e6eae17b..1b56d3404 100644 --- a/hpy/devel/include/universal/hpyfunc_trampolines.h +++ b/hpy/devel/include/universal/hpyfunc_trampolines.h @@ -27,6 +27,13 @@ typedef struct { cpy_PyObject *result; } _HPyFunc_args_KEYWORDS; +typedef struct { + cpy_PyObject *self; + cpy_PyObject *args; + cpy_PyObject *kw; + int result; +} _HPyFunc_args_INITPROC; + #define _HPyFunc_TRAMPOLINE_HPyFunc_NOARGS(SYM, IMPL) \ static cpy_PyObject * \ @@ -70,5 +77,15 @@ typedef struct { return a.result; \ } +#define _HPyFunc_TRAMPOLINE_HPyFunc_INITPROC(SYM, IMPL) \ + static int \ + SYM(cpy_PyObject *self, cpy_PyObject *args, cpy_PyObject *kw) \ + { \ + _HPyFunc_args_INITPROC a = { self, args, kw }; \ + _HPy_CallRealFunctionFromTrampoline( \ + _ctx_for_trampolines, HPyFunc_INITPROC, IMPL, &a); \ + return a.result; \ + } + #endif // HPY_UNIVERSAL_HPYFUNC_TRAMPOLINES_H diff --git a/hpy/tools/autogen/hpyfunc.py b/hpy/tools/autogen/hpyfunc.py index bfbfd8ba3..8cfccb727 100644 --- a/hpy/tools/autogen/hpyfunc.py +++ b/hpy/tools/autogen/hpyfunc.py @@ -3,6 +3,7 @@ from .autogenfile import AutoGenFile from .parse import toC, find_typedecl +SPECIAL_CASES = ('NOARGS', 'O', 'VARARGS', 'KEYWORDS', 'INITPROC') class autogen_hpyfunc_declare_h(AutoGenFile): PATH = 'hpy/devel/include/common/autogen_hpyfunc_declare.h' @@ -48,7 +49,7 @@ def generate(self): w = lines.append for hpyfunc in self.api.hpyfunc_typedefs: NAME = hpyfunc.base_name().upper() - if NAME in ['NOARGS', 'O', 'VARARGS', 'KEYWORDS']: + if NAME in SPECIAL_CASES: continue # tramp_node = deepcopy(hpyfunc.node.type.type) @@ -99,7 +100,7 @@ def generate(self): for hpyfunc in self.api.hpyfunc_typedefs: name = hpyfunc.base_name() NAME = name.upper() - if NAME in ['NOARGS', 'O', 'VARARGS', 'KEYWORDS']: + if NAME in SPECIAL_CASES: continue # c_ret_type = toC(hpyfunc.return_type()) @@ -137,7 +138,7 @@ def generate(self): for hpyfunc in self.api.hpyfunc_typedefs: name = hpyfunc.base_name() NAME = name.upper() - if NAME in ['NOARGS', 'O', 'VARARGS', 'KEYWORDS']: + if NAME in SPECIAL_CASES: continue # tramp_node = deepcopy(hpyfunc.node.type.type) diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 4af7850ab..5998d64a3 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -194,4 +194,5 @@ typedef HPy (*HPyFunc_getiterfunc)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_iternextfunc)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_descrgetfunc)(HPyContext ctx, HPy, HPy, HPy); typedef int (*HPyFunc_descrsetfunc)(HPyContext ctx, HPy, HPy, HPy); -typedef int (*HPyFunc_initproc)(HPyContext ctx, HPy, HPy, HPy); +typedef int (*HPyFunc_initproc)(HPyContext ctx, HPy self, + HPy *args, HPy_ssize_t nargs, HPy kw); diff --git a/hpy/universal/src/autogen_ctx_call.i b/hpy/universal/src/autogen_ctx_call.i index 7a41b471f..9a6ea1227 100644 --- a/hpy/universal/src/autogen_ctx_call.i +++ b/hpy/universal/src/autogen_ctx_call.i @@ -146,9 +146,3 @@ a->result = f(ctx, _py2h(a->arg0), _py2h(a->arg1), _py2h(a->arg2)); return; } - case HPyFunc_INITPROC: { - HPyFunc_initproc f = (HPyFunc_initproc)func; - _HPyFunc_args_INITPROC *a = (_HPyFunc_args_INITPROC*)args; - a->result = f(ctx, _py2h(a->arg0), _py2h(a->arg1), _py2h(a->arg2)); - return; - } diff --git a/hpy/universal/src/ctx_meth.c b/hpy/universal/src/ctx_meth.c index 20ce3669b..77f4b72ae 100644 --- a/hpy/universal/src/ctx_meth.c +++ b/hpy/universal/src/ctx_meth.c @@ -40,6 +40,17 @@ ctx_CallRealFunctionFromTrampoline(HPyContext ctx, HPyFunc_Signature sig, 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 = alloca(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: abort(); // XXX diff --git a/test/test_hpytype.py b/test/test_hpytype.py index df3ee8ad4..49e9c7265 100644 --- a/test/test_hpytype.py +++ b/test/test_hpytype.py @@ -173,6 +173,56 @@ def test_HPyType_GenericNew(self): p = mod.Point() assert p.foo() == 0 + def test_tp_init(self): + mod = self.make_module(""" + typedef struct { + HPyObject_HEAD + long x; + long y; + } PointObject; + + HPyDef_SLOT(Point_new, HPy_tp_new, HPyType_GenericNew, HPyFunc_KEYWORDS) + + HPyDef_SLOT(Point_init, HPy_tp_init, Point_init_impl, HPyFunc_INITPROC) + static int Point_init_impl(HPyContext ctx, HPy self, HPy *args, + HPy_ssize_t nargs, HPy kw) + { + long x, y; + if (!HPyArg_Parse(ctx, args, nargs, "ll", &x, &y)) + return -1; + + PointObject *p = HPy_CAST(ctx, PointObject, self); + p->x = x; + p->y = y; + return 0; + } + + HPyDef_METH(Point_foo, "foo", Point_foo_impl, HPyFunc_NOARGS) + static HPy Point_foo_impl(HPyContext ctx, HPy self) + { + PointObject *point = HPy_CAST(ctx, PointObject, self); + return HPyLong_FromLong(ctx, point->x*10 + point->y); + } + + static HPyDef *Point_defines[] = { + &Point_new, + &Point_init, + &Point_foo, + NULL + }; + static HPyType_Spec Point_spec = { + .name = "mytest.Point", + .basicsize = sizeof(PointObject), + .defines = Point_defines + }; + + @EXPORT_TYPE("Point", Point_spec) + @INIT + """) + p = mod.Point(1, 2) + assert p.foo() == 12 + + def test_getitem(self): mod = self.make_module(""" From 70d663cc7f954c85d0d00a3b1adc78ae515db158 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 7 Aug 2020 15:28:36 +0200 Subject: [PATCH 3/6] HPyList_Check(), HPyDict_Check(), HPy_Length() --- hpy/devel/include/common/autogen_impl.h | 15 +++++++++++++++ hpy/devel/include/universal/autogen_ctx.h | 3 +++ .../include/universal/autogen_trampolines.h | 12 ++++++++++++ hpy/tools/autogen/parse.py | 1 + hpy/tools/autogen/public_api.h | 4 ++++ hpy/universal/src/autogen_ctx_def.h | 3 +++ test/test_hpydict.py | 19 +++++++++++++++++++ test/test_hpylist.py | 19 +++++++++++++++++++ test/test_object.py | 17 +++++++++++++++++ 9 files changed, 93 insertions(+) diff --git a/hpy/devel/include/common/autogen_impl.h b/hpy/devel/include/common/autogen_impl.h index 7bbbb98b8..4c95a094d 100644 --- a/hpy/devel/include/common/autogen_impl.h +++ b/hpy/devel/include/common/autogen_impl.h @@ -53,6 +53,11 @@ HPyAPI_STORAGE double _HPy_IMPL_NAME(Float_AsDouble)(HPyContext ctx, HPy h) return PyFloat_AsDouble(_h2py(h)); } +HPyAPI_STORAGE HPy_ssize_t _HPy_IMPL_NAME_NOPREFIX(Length)(HPyContext ctx, HPy h) +{ + return PyObject_Length(_h2py(h)); +} + HPyAPI_STORAGE int _HPy_IMPL_NAME(Number_Check)(HPyContext ctx, HPy h) { return PyNumber_Check(_h2py(h)); @@ -363,6 +368,11 @@ HPyAPI_STORAGE HPy _HPy_IMPL_NAME(Unicode_FromWideChar)(HPyContext ctx, const wc return _py2h(PyUnicode_FromWideChar(w, size)); } +HPyAPI_STORAGE int _HPy_IMPL_NAME(List_Check)(HPyContext ctx, HPy h) +{ + return PyList_Check(_h2py(h)); +} + HPyAPI_STORAGE HPy _HPy_IMPL_NAME(List_New)(HPyContext ctx, HPy_ssize_t len) { return _py2h(PyList_New(len)); @@ -373,6 +383,11 @@ HPyAPI_STORAGE int _HPy_IMPL_NAME(List_Append)(HPyContext ctx, HPy h_list, HPy h return PyList_Append(_h2py(h_list), _h2py(h_item)); } +HPyAPI_STORAGE int _HPy_IMPL_NAME(Dict_Check)(HPyContext ctx, HPy h) +{ + return PyDict_Check(_h2py(h)); +} + HPyAPI_STORAGE HPy _HPy_IMPL_NAME(Dict_New)(HPyContext ctx) { return _py2h(PyDict_New()); diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index 102f4d8fc..42902adcf 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -33,6 +33,7 @@ struct _HPyContext_s { long (*ctx_Long_AsLong)(HPyContext ctx, HPy h); HPy (*ctx_Float_FromDouble)(HPyContext ctx, double v); double (*ctx_Float_AsDouble)(HPyContext ctx, HPy h); + HPy_ssize_t (*ctx_Length)(HPyContext ctx, HPy h); int (*ctx_Number_Check)(HPyContext ctx, HPy h); HPy (*ctx_Add)(HPyContext ctx, HPy h1, HPy h2); HPy (*ctx_Subtract)(HPyContext ctx, HPy h1, HPy h2); @@ -104,8 +105,10 @@ struct _HPyContext_s { int (*ctx_Unicode_Check)(HPyContext ctx, HPy h); HPy (*ctx_Unicode_AsUTF8String)(HPyContext ctx, HPy h); HPy (*ctx_Unicode_FromWideChar)(HPyContext ctx, const wchar_t *w, HPy_ssize_t size); + int (*ctx_List_Check)(HPyContext ctx, HPy h); HPy (*ctx_List_New)(HPyContext ctx, HPy_ssize_t len); int (*ctx_List_Append)(HPyContext ctx, HPy h_list, HPy h_item); + int (*ctx_Dict_Check)(HPyContext ctx, HPy h); HPy (*ctx_Dict_New)(HPyContext ctx); int (*ctx_Dict_SetItem)(HPyContext ctx, HPy h_dict, HPy h_key, HPy h_val); HPy (*ctx_Dict_GetItem)(HPyContext ctx, HPy h_dict, HPy h_key); diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index 5c5467383..366e61c63 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -56,6 +56,10 @@ static inline double HPyFloat_AsDouble(HPyContext ctx, HPy h) { return ctx->ctx_Float_AsDouble ( ctx, h ); } +static inline HPy_ssize_t HPy_Length(HPyContext ctx, HPy h) { + return ctx->ctx_Length ( ctx, h ); +} + static inline int HPyNumber_Check(HPyContext ctx, HPy h) { return ctx->ctx_Number_Check ( ctx, h ); } @@ -336,6 +340,10 @@ static inline HPy HPyUnicode_FromWideChar(HPyContext ctx, const wchar_t *w, HPy_ return ctx->ctx_Unicode_FromWideChar ( ctx, w, size ); } +static inline int HPyList_Check(HPyContext ctx, HPy h) { + return ctx->ctx_List_Check ( ctx, h ); +} + static inline HPy HPyList_New(HPyContext ctx, HPy_ssize_t len) { return ctx->ctx_List_New ( ctx, len ); } @@ -344,6 +352,10 @@ static inline int HPyList_Append(HPyContext ctx, HPy h_list, HPy h_item) { return ctx->ctx_List_Append ( ctx, h_list, h_item ); } +static inline int HPyDict_Check(HPyContext ctx, HPy h) { + return ctx->ctx_Dict_Check ( ctx, h ); +} + static inline HPy HPyDict_New(HPyContext ctx) { return ctx->ctx_Dict_New ( ctx ); } diff --git a/hpy/tools/autogen/parse.py b/hpy/tools/autogen/parse.py index d40f4b007..efd16b8d7 100644 --- a/hpy/tools/autogen/parse.py +++ b/hpy/tools/autogen/parse.py @@ -124,6 +124,7 @@ def _visit_hpyfunc_typedef(self, node): 'HPy_SetItem': 'PyObject_SetItem', 'HPy_SetItem_i': None, 'HPy_SetItem_s': None, + 'HPy_Length': 'PyObject_Length', '_HPy_Cast': None, 'HPy_FromPyObject': None, 'HPy_AsPyObject': None, diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 5998d64a3..99d6cba85 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -41,6 +41,8 @@ HPy HPyFloat_FromDouble(HPyContext ctx, double v); double HPyFloat_AsDouble(HPyContext ctx, HPy h); /* abstract.h */ +HPy_ssize_t HPy_Length(HPyContext ctx, HPy h); + int HPyNumber_Check(HPyContext ctx, HPy h); HPy HPy_Add(HPyContext ctx, HPy h1, HPy h2); HPy HPy_Subtract(HPyContext ctx, HPy h1, HPy h2); @@ -133,10 +135,12 @@ HPy HPyUnicode_AsUTF8String(HPyContext ctx, HPy h); HPy HPyUnicode_FromWideChar(HPyContext ctx, const wchar_t *w, HPy_ssize_t size); /* listobject.h */ +int HPyList_Check(HPyContext ctx, HPy h); HPy HPyList_New(HPyContext ctx, HPy_ssize_t len); int HPyList_Append(HPyContext ctx, HPy h_list, HPy h_item); /* dictobject.h */ +int HPyDict_Check(HPyContext ctx, HPy h); HPy HPyDict_New(HPyContext ctx); // TODO: Move HPyDict_SetItem and _GetItem (we have HPy_SetItem and _GetItem) // out of the base API. diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index a1c2a4ca2..85529ad66 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -33,6 +33,7 @@ struct _HPyContext_s global_ctx = { .ctx_Long_AsLong = &ctx_Long_AsLong, .ctx_Float_FromDouble = &ctx_Float_FromDouble, .ctx_Float_AsDouble = &ctx_Float_AsDouble, + .ctx_Length = &ctx_Length, .ctx_Number_Check = &ctx_Number_Check, .ctx_Add = &ctx_Add, .ctx_Subtract = &ctx_Subtract, @@ -104,8 +105,10 @@ struct _HPyContext_s global_ctx = { .ctx_Unicode_Check = &ctx_Unicode_Check, .ctx_Unicode_AsUTF8String = &ctx_Unicode_AsUTF8String, .ctx_Unicode_FromWideChar = &ctx_Unicode_FromWideChar, + .ctx_List_Check = &ctx_List_Check, .ctx_List_New = &ctx_List_New, .ctx_List_Append = &ctx_List_Append, + .ctx_Dict_Check = &ctx_Dict_Check, .ctx_Dict_New = &ctx_Dict_New, .ctx_Dict_SetItem = &ctx_Dict_SetItem, .ctx_Dict_GetItem = &ctx_Dict_GetItem, diff --git a/test/test_hpydict.py b/test/test_hpydict.py index 437055432..d87e0bbc5 100644 --- a/test/test_hpydict.py +++ b/test/test_hpydict.py @@ -2,6 +2,25 @@ class TestDict(HPyTest): + def test_Check(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext ctx, HPy self, HPy arg) + { + if (HPyDict_Check(ctx, arg)) + return HPy_Dup(ctx, ctx->h_True); + return HPy_Dup(ctx, ctx->h_False); + } + @EXPORT(f) + @INIT + """) + class MyDict(dict): + pass + + assert mod.f({}) is True + assert mod.f([]) is False + assert mod.f(MyDict()) is True + def test_New(self): mod = self.make_module(""" HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) diff --git a/test/test_hpylist.py b/test/test_hpylist.py index 26bea23a0..61723a617 100644 --- a/test/test_hpylist.py +++ b/test/test_hpylist.py @@ -2,6 +2,25 @@ class TestList(HPyTest): + def test_Check(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext ctx, HPy self, HPy arg) + { + if (HPyList_Check(ctx, arg)) + return HPy_Dup(ctx, ctx->h_True); + return HPy_Dup(ctx, ctx->h_False); + } + @EXPORT(f) + @INIT + """) + class MyList(list): + pass + + assert mod.f([]) is True + assert mod.f('hello') is False + assert mod.f(MyList()) is True + def test_New(self): mod = self.make_module(""" HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) diff --git a/test/test_object.py b/test/test_object.py index f09f8039f..b71b7e9b5 100644 --- a/test/test_object.py +++ b/test/test_object.py @@ -443,3 +443,20 @@ def test_setitem_s(self): with pytest.raises(TypeError): mod.f([]) + + def test_length(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext ctx, HPy self, HPy arg) + { + HPy_ssize_t result; + result = HPy_Length(ctx, arg); + if (result < 0) + return HPy_NULL; + return HPyLong_FromSsize_t(ctx, result); + } + @EXPORT(f) + @INIT + """) + assert mod.f([5,6,7,8]) == 4 + assert mod.f({"a": 1}) == 1 From ac1910c7348f2a94542cceccf6b0c234836bc161 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 7 Aug 2020 17:27:56 +0200 Subject: [PATCH 4/6] (anto, arigo) implement 'HPy_tp_destroy', which is a variation on 'dealloc'. This one is meant to be a "lightweight destructor" from PyPy. --- .../include/common/autogen_hpyfunc_declare.h | 4 +- hpy/devel/include/common/hpyfunc.h | 3 +- hpy/devel/include/common/typeslots.h | 11 ++-- .../cpython/autogen_hpyfunc_trampolines.h | 5 -- .../include/cpython/hpyfunc_trampolines.h | 8 +++ hpy/devel/include/universal/autogen_ctx.h | 1 + .../universal/autogen_hpyfunc_trampolines.h | 13 ---- .../include/universal/autogen_trampolines.h | 4 ++ .../include/universal/hpyfunc_trampolines.h | 10 +++ hpy/devel/src/runtime/ctx_type.c | 11 +++- hpy/tools/autogen/hpyfunc.py | 3 +- hpy/tools/autogen/parse.py | 1 + hpy/tools/autogen/public_api.h | 6 +- hpy/universal/src/autogen_ctx_call.i | 6 -- hpy/universal/src/autogen_ctx_def.h | 1 + hpy/universal/src/ctx_meth.c | 14 +++++ hpy/universal/src/ctx_meth.h | 3 + test/test_hpytype.py | 63 ++++++++++++++++++- 18 files changed, 130 insertions(+), 37 deletions(-) diff --git a/hpy/devel/include/common/autogen_hpyfunc_declare.h b/hpy/devel/include/common/autogen_hpyfunc_declare.h index bfc96042d..3b72ad484 100644 --- a/hpy/devel/include/common/autogen_hpyfunc_declare.h +++ b/hpy/devel/include/common/autogen_hpyfunc_declare.h @@ -23,7 +23,6 @@ #define _HPyFunc_DECLARE_HPyFunc_SSIZESSIZEOBJARGPROC(SYM) static int SYM(HPyContext ctx, HPy, HPy_ssize_t, HPy_ssize_t, HPy) #define _HPyFunc_DECLARE_HPyFunc_OBJOBJARGPROC(SYM) static int SYM(HPyContext ctx, HPy, HPy, HPy) #define _HPyFunc_DECLARE_HPyFunc_FREEFUNC(SYM) static void SYM(HPyContext ctx, void *) -#define _HPyFunc_DECLARE_HPyFunc_DESTRUCTOR(SYM) static void SYM(HPyContext ctx, HPy) #define _HPyFunc_DECLARE_HPyFunc_GETATTRFUNC(SYM) static HPy SYM(HPyContext ctx, HPy, char *) #define _HPyFunc_DECLARE_HPyFunc_GETATTROFUNC(SYM) static HPy SYM(HPyContext ctx, HPy, HPy) #define _HPyFunc_DECLARE_HPyFunc_SETATTRFUNC(SYM) static int SYM(HPyContext ctx, HPy, char *, HPy) @@ -36,6 +35,7 @@ #define _HPyFunc_DECLARE_HPyFunc_DESCRGETFUNC(SYM) static HPy SYM(HPyContext ctx, HPy, HPy, HPy) #define _HPyFunc_DECLARE_HPyFunc_DESCRSETFUNC(SYM) static int SYM(HPyContext ctx, HPy, HPy, HPy) #define _HPyFunc_DECLARE_HPyFunc_INITPROC(SYM) static int SYM(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, HPy kw) +#define _HPyFunc_DECLARE_HPyFunc_DESTROYFUNC(SYM) static void SYM(void *) typedef HPy (*HPyFunc_noargs)(HPyContext ctx, HPy self); typedef HPy (*HPyFunc_o)(HPyContext ctx, HPy self, HPy arg); @@ -52,7 +52,6 @@ typedef int (*HPyFunc_ssizeobjargproc)(HPyContext ctx, HPy, HPy_ssize_t, HPy); typedef int (*HPyFunc_ssizessizeobjargproc)(HPyContext ctx, HPy, HPy_ssize_t, HPy_ssize_t, HPy); typedef int (*HPyFunc_objobjargproc)(HPyContext ctx, HPy, HPy, HPy); typedef void (*HPyFunc_freefunc)(HPyContext ctx, void *); -typedef void (*HPyFunc_destructor)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_getattrfunc)(HPyContext ctx, HPy, char *); typedef HPy (*HPyFunc_getattrofunc)(HPyContext ctx, HPy, HPy); typedef int (*HPyFunc_setattrfunc)(HPyContext ctx, HPy, char *, HPy); @@ -65,3 +64,4 @@ typedef HPy (*HPyFunc_iternextfunc)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_descrgetfunc)(HPyContext ctx, HPy, HPy, HPy); typedef int (*HPyFunc_descrsetfunc)(HPyContext ctx, HPy, HPy, HPy); typedef int (*HPyFunc_initproc)(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, HPy kw); +typedef void (*HPyFunc_destroyfunc)(void *); diff --git a/hpy/devel/include/common/hpyfunc.h b/hpy/devel/include/common/hpyfunc.h index cea9f8d6b..add699050 100644 --- a/hpy/devel/include/common/hpyfunc.h +++ b/hpy/devel/include/common/hpyfunc.h @@ -7,6 +7,8 @@ typedef enum { HPyFunc_NOARGS = 3, // METH_NOARGS HPyFunc_O = 4, // METH_O + HPyFunc_DESTROYFUNC, + HPyFunc_UNARYFUNC, HPyFunc_BINARYFUNC, HPyFunc_TERNARYFUNC, @@ -18,7 +20,6 @@ typedef enum { HPyFunc_SSIZESSIZEOBJARGPROC, HPyFunc_OBJOBJARGPROC, HPyFunc_FREEFUNC, - HPyFunc_DESTRUCTOR, HPyFunc_GETATTRFUNC, HPyFunc_GETATTROFUNC, HPyFunc_SETATTRFUNC, diff --git a/hpy/devel/include/common/typeslots.h b/hpy/devel/include/common/typeslots.h index 5ff52a405..63a29a498 100644 --- a/hpy/devel/include/common/typeslots.h +++ b/hpy/devel/include/common/typeslots.h @@ -47,12 +47,12 @@ typedef enum { HPy_sq_item = 44, HPy_sq_length = 45, HPy_sq_repeat = 46, - HPy_tp_alloc = 47, + /*HPy_tp_alloc = 47,*/ HPy_tp_base = 48, HPy_tp_bases = 49, HPy_tp_call = 50, HPy_tp_clear = 51, - HPy_tp_dealloc = 52, + /*HPy_tp_dealloc = 52,*/ HPy_tp_del = 53, HPy_tp_descr_get = 54, HPy_tp_descr_set = 55, @@ -74,13 +74,16 @@ typedef enum { HPy_tp_traverse = 71, HPy_tp_members = 72, HPy_tp_getset = 73, - HPy_tp_free = 74, + /*HPy_tp_free = 74,*/ HPy_nb_matrix_multiply = 75, HPy_nb_inplace_matrix_multiply = 76, HPy_am_await = 77, HPy_am_aiter = 78, HPy_am_anext = 79, - HPy_tp_finalize = 80 + HPy_tp_finalize = 80, + + /* extra HPy slots */ + HPy_tp_destroy = 1000, } HPySlot_Slot; #endif // HPY_UNIVERSAL_TYPESLOTS_H diff --git a/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h b/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h index f38f8bbd4..4a936a010 100644 --- a/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h +++ b/hpy/devel/include/cpython/autogen_hpyfunc_trampolines.h @@ -63,11 +63,6 @@ { \ return (IMPL(_HPyGetContext(), arg0)); \ } -#define _HPyFunc_TRAMPOLINE_HPyFunc_DESTRUCTOR(SYM, IMPL) \ - static void SYM(cpy_PyObject *arg0) \ - { \ - return (IMPL(_HPyGetContext(), _py2h(arg0))); \ - } #define _HPyFunc_TRAMPOLINE_HPyFunc_GETATTRFUNC(SYM, IMPL) \ static cpy_PyObject *SYM(cpy_PyObject *arg0, char *arg1) \ { \ diff --git a/hpy/devel/include/cpython/hpyfunc_trampolines.h b/hpy/devel/include/cpython/hpyfunc_trampolines.h index 44b20711c..2e943cae2 100644 --- a/hpy/devel/include/cpython/hpyfunc_trampolines.h +++ b/hpy/devel/include/cpython/hpyfunc_trampolines.h @@ -52,4 +52,12 @@ items, nargs, _py2h(kw)); \ } +#define _HPyFunc_TRAMPOLINE_HPyFunc_DESTROYFUNC(SYM, IMPL) \ + static void \ + SYM(PyObject *self) \ + { \ + IMPL(self); \ + Py_TYPE(self)->tp_free(self); \ + } + #endif // HPY_CPYTHON_HPYFUNC_TRAMPOLINES_H diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index 42902adcf..5f304059a 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -115,4 +115,5 @@ struct _HPyContext_s { HPy (*ctx_FromPyObject)(HPyContext ctx, cpy_PyObject *obj); cpy_PyObject *(*ctx_AsPyObject)(HPyContext ctx, HPy h); void (*ctx_CallRealFunctionFromTrampoline)(HPyContext ctx, HPyFunc_Signature sig, void *func, void *args); + void (*ctx_CallDestroyAndThenDealloc)(HPyContext ctx, void *func, cpy_PyObject *self); }; diff --git a/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h b/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h index 1016229a6..7e3482b6f 100644 --- a/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h +++ b/hpy/devel/include/universal/autogen_hpyfunc_trampolines.h @@ -174,19 +174,6 @@ typedef struct { return; \ } -typedef struct { - cpy_PyObject *arg0; -} _HPyFunc_args_DESTRUCTOR; - -#define _HPyFunc_TRAMPOLINE_HPyFunc_DESTRUCTOR(SYM, IMPL) \ - static void SYM(cpy_PyObject *arg0) \ - { \ - _HPyFunc_args_DESTRUCTOR a = { arg0 }; \ - _HPy_CallRealFunctionFromTrampoline( \ - _ctx_for_trampolines, HPyFunc_DESTRUCTOR, IMPL, &a); \ - return; \ - } - typedef struct { cpy_PyObject *arg0; char *arg1; diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index 366e61c63..8af322e44 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -380,3 +380,7 @@ static inline void _HPy_CallRealFunctionFromTrampoline(HPyContext ctx, HPyFunc_S ctx->ctx_CallRealFunctionFromTrampoline ( ctx, sig, func, args ); } +static inline void _HPy_CallDestroyAndThenDealloc(HPyContext ctx, void *func, cpy_PyObject *self) { + ctx->ctx_CallDestroyAndThenDealloc ( ctx, func, self ); +} + diff --git a/hpy/devel/include/universal/hpyfunc_trampolines.h b/hpy/devel/include/universal/hpyfunc_trampolines.h index 1b56d3404..f9c6fdfd4 100644 --- a/hpy/devel/include/universal/hpyfunc_trampolines.h +++ b/hpy/devel/include/universal/hpyfunc_trampolines.h @@ -87,5 +87,15 @@ typedef struct { return a.result; \ } +/* special case: this function is used as 'tp_dealloc', but from the user + point of view the slot is HPy_tp_destroy. */ +#define _HPyFunc_TRAMPOLINE_HPyFunc_DESTROYFUNC(SYM, IMPL) \ + static void \ + SYM(cpy_PyObject *self) \ + { \ + _HPy_CallDestroyAndThenDealloc( \ + _ctx_for_trampolines, IMPL, self); \ + } + #endif // HPY_UNIVERSAL_HPYFUNC_TRAMPOLINES_H diff --git a/hpy/devel/src/runtime/ctx_type.c b/hpy/devel/src/runtime/ctx_type.c index 3407c6c1c..01b6b5843 100644 --- a/hpy/devel/src/runtime/ctx_type.c +++ b/hpy/devel/src/runtime/ctx_type.c @@ -68,6 +68,15 @@ legacy_slots_count(PyType_Slot slots[], HPy_ssize_t *slot_count, } } +static int +hpy_slot_to_cpy_slot(HPySlot_Slot src) +{ + switch (src) { + case HPy_tp_destroy: return Py_tp_dealloc; + default: return src; /* same numeric value by default */ + } +} + /* * Create a PyMethodDef which contains: @@ -166,7 +175,7 @@ create_slot_defs(HPyType_Spec *hpyspec) if (src->kind != HPyDef_Kind_Slot) continue; PyType_Slot *dst = &result[dst_idx++]; - dst->slot = src->slot.slot; + dst->slot = hpy_slot_to_cpy_slot(src->slot.slot); dst->pfunc = src->slot.cpy_trampoline; } } diff --git a/hpy/tools/autogen/hpyfunc.py b/hpy/tools/autogen/hpyfunc.py index 8cfccb727..f36cb38a9 100644 --- a/hpy/tools/autogen/hpyfunc.py +++ b/hpy/tools/autogen/hpyfunc.py @@ -3,7 +3,8 @@ from .autogenfile import AutoGenFile from .parse import toC, find_typedecl -SPECIAL_CASES = ('NOARGS', 'O', 'VARARGS', 'KEYWORDS', 'INITPROC') +SPECIAL_CASES = ('NOARGS', 'O', 'VARARGS', 'KEYWORDS', 'INITPROC', + 'DESTROYFUNC') class autogen_hpyfunc_declare_h(AutoGenFile): PATH = 'hpy/devel/include/common/autogen_hpyfunc_declare.h' diff --git a/hpy/tools/autogen/parse.py b/hpy/tools/autogen/parse.py index efd16b8d7..2183892ce 100644 --- a/hpy/tools/autogen/parse.py +++ b/hpy/tools/autogen/parse.py @@ -129,6 +129,7 @@ def _visit_hpyfunc_typedef(self, node): 'HPy_FromPyObject': None, 'HPy_AsPyObject': None, '_HPy_CallRealFunctionFromTrampoline': None, + '_HPy_CallDestroyAndThenDealloc': None, 'HPyErr_Occurred': None, 'HPy_Add': 'PyNumber_Add', 'HPy_Subtract': 'PyNumber_Subtract', diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 99d6cba85..e2b09b4c6 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -158,6 +158,9 @@ void _HPy_CallRealFunctionFromTrampoline(HPyContext ctx, HPyFunc_Signature sig, void *func, void *args); +void _HPy_CallDestroyAndThenDealloc(HPyContext ctx, + void *func, + cpy_PyObject *self); @@ -186,7 +189,6 @@ typedef int (*HPyFunc_ssizeobjargproc)(HPyContext ctx, HPy, HPy_ssize_t, HPy); typedef int (*HPyFunc_ssizessizeobjargproc)(HPyContext ctx, HPy, HPy_ssize_t, HPy_ssize_t, HPy); typedef int (*HPyFunc_objobjargproc)(HPyContext ctx, HPy, HPy, HPy); typedef void (*HPyFunc_freefunc)(HPyContext ctx, void *); -typedef void (*HPyFunc_destructor)(HPyContext ctx, HPy); typedef HPy (*HPyFunc_getattrfunc)(HPyContext ctx, HPy, char *); typedef HPy (*HPyFunc_getattrofunc)(HPyContext ctx, HPy, HPy); typedef int (*HPyFunc_setattrfunc)(HPyContext ctx, HPy, char *, HPy); @@ -200,3 +202,5 @@ typedef HPy (*HPyFunc_descrgetfunc)(HPyContext ctx, HPy, HPy, HPy); typedef int (*HPyFunc_descrsetfunc)(HPyContext ctx, HPy, HPy, HPy); typedef int (*HPyFunc_initproc)(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, HPy kw); + +typedef void (*HPyFunc_destroyfunc)(void *); diff --git a/hpy/universal/src/autogen_ctx_call.i b/hpy/universal/src/autogen_ctx_call.i index 9a6ea1227..789d5a9d1 100644 --- a/hpy/universal/src/autogen_ctx_call.i +++ b/hpy/universal/src/autogen_ctx_call.i @@ -74,12 +74,6 @@ f(ctx, a->arg0); return; } - case HPyFunc_DESTRUCTOR: { - HPyFunc_destructor f = (HPyFunc_destructor)func; - _HPyFunc_args_DESTRUCTOR *a = (_HPyFunc_args_DESTRUCTOR*)args; - f(ctx, _py2h(a->arg0)); - return; - } case HPyFunc_GETATTRFUNC: { HPyFunc_getattrfunc f = (HPyFunc_getattrfunc)func; _HPyFunc_args_GETATTRFUNC *a = (_HPyFunc_args_GETATTRFUNC*)args; diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 85529ad66..ab7d3f9d8 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -115,4 +115,5 @@ struct _HPyContext_s global_ctx = { .ctx_FromPyObject = &ctx_FromPyObject, .ctx_AsPyObject = &ctx_AsPyObject, .ctx_CallRealFunctionFromTrampoline = &ctx_CallRealFunctionFromTrampoline, + .ctx_CallDestroyAndThenDealloc = &ctx_CallDestroyAndThenDealloc, }; diff --git a/hpy/universal/src/ctx_meth.c b/hpy/universal/src/ctx_meth.c index 77f4b72ae..91f2d24a5 100644 --- a/hpy/universal/src/ctx_meth.c +++ b/hpy/universal/src/ctx_meth.c @@ -1,3 +1,4 @@ +#include #include "ctx_meth.h" #include "handles.h" @@ -56,3 +57,16 @@ ctx_CallRealFunctionFromTrampoline(HPyContext ctx, HPyFunc_Signature sig, abort(); // XXX } } + + +HPyAPI_STORAGE void +ctx_CallDestroyAndThenDealloc(HPyContext ctx, void *func, PyObject *self) +{ + /* this is _HPy_Cast(_py2h(self)), but this just returns self for now */ + void *obj = (void *)self; + + HPyFunc_destroyfunc f = (HPyFunc_destroyfunc)func; + f(obj); + + Py_TYPE(self)->tp_free(self); +} diff --git a/hpy/universal/src/ctx_meth.h b/hpy/universal/src/ctx_meth.h index acec74efc..6d7ee5184 100644 --- a/hpy/universal/src/ctx_meth.h +++ b/hpy/universal/src/ctx_meth.h @@ -4,3 +4,6 @@ HPyAPI_STORAGE void ctx_CallRealFunctionFromTrampoline(HPyContext ctx, HPyFunc_Signature sig, void *func, void *args); + +HPyAPI_STORAGE void +ctx_CallDestroyAndThenDealloc(HPyContext ctx, void *func, PyObject *self); diff --git a/test/test_hpytype.py b/test/test_hpytype.py index 49e9c7265..490c7599e 100644 --- a/test/test_hpytype.py +++ b/test/test_hpytype.py @@ -222,9 +222,7 @@ def test_tp_init(self): p = mod.Point(1, 2) assert p.foo() == 12 - - - def test_getitem(self): + def test_sq_item(self): mod = self.make_module(""" HPyDef_SLOT(Dummy_getitem, HPy_sq_item, Dummy_getitem_impl, HPyFunc_SSIZEARGFUNC); static HPy Dummy_getitem_impl(HPyContext ctx, HPy self, HPy_ssize_t idx) @@ -247,3 +245,62 @@ def test_getitem(self): d = mod.Dummy() assert d[4] == 8 assert d[21] == 42 + + def test_tp_destroy(self): + import gc + mod = self.make_module(""" + typedef struct { + HPyObject_HEAD + long x, y; + } PointObject; + + static long destroyed_x; + + HPyDef_SLOT(Point_new, HPy_tp_new, Point_new_impl, HPyFunc_KEYWORDS) + static HPy Point_new_impl(HPyContext ctx, HPy cls, HPy *args, + HPy_ssize_t nargs, HPy kw) + { + PointObject *point; + HPy h_point = HPy_New(ctx, cls, &point); + if (HPy_IsNull(h_point)) + return HPy_NULL; + point->x = 7; + point->y = 3; + return h_point; + } + + HPyDef_SLOT(Point_destroy, HPy_tp_destroy, Point_destroy_impl, HPyFunc_DESTROYFUNC) + static void Point_destroy_impl(void *obj) + { + PointObject *point = (PointObject *)obj; + destroyed_x += point->x; + } + + static HPyDef *Point_defines[] = { + &Point_new, + &Point_destroy, + NULL + }; + static HPyType_Spec Point_spec = { + .name = "mytest.Point", + .basicsize = sizeof(PointObject), + .defines = Point_defines + }; + + HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) + static HPy f_impl(HPyContext ctx, HPy self) + { + return HPyLong_FromLong(ctx, destroyed_x); + } + + @EXPORT_TYPE("Point", Point_spec) + @EXPORT(f) + @INIT + """) + point = mod.Point() + assert mod.f() == 0 + del point + gc.collect() + assert mod.f() == 7 + gc.collect() + assert mod.f() == 7 From f05ef4a9abb5502c8be112ca8e3ffe8904086c84 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 7 Aug 2020 17:34:50 +0200 Subject: [PATCH 5/6] (anto, arigo) write comments in porting-guide --- docs/porting-guide.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 35957bff5..f7e065112 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -6,3 +6,7 @@ xxx `PyModule_AddObject()`: replace with a regular `HPy_SetAttr_s()`. There is no `HPyModule_AddObject()` because it has an unusual refcount behaviour (stealing a reference but only when it returns 0). +Py_tp_dealloc becomes HPy_tp_destroy. We changed the name a little bit +because only "lightweight" destructors are supported. Use tp_finalize if +you really need to do things with the context or with the handle of the +object. From 2d3d96ebc01593fbdc3b9ab2436860a00057f126 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 7 Aug 2020 18:12:28 +0200 Subject: [PATCH 6/6] (anto, arigo) how to build lists (and tuples and bytes) in HPy --- docs/porting-guide.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index f7e065112..5e4beefbf 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -10,3 +10,21 @@ Py_tp_dealloc becomes HPy_tp_destroy. We changed the name a little bit because only "lightweight" destructors are supported. Use tp_finalize if you really need to do things with the context or with the handle of the object. + +PyList_New(5)/PyList_SET_ITEM() becomes:: + + HPyListBuilder builder = HPyListBuilder_New(ctx, 5); + HPyListBuilder_Set(ctx, builder, 0, h_item0); + ... + HPyListBuilder_Append(ctx, builder, h_item5); + ... + HPy h_list = HPyListBuilder_Build(ctx, builder); + +For lists of (say) integers:: + + HPyListBuilder_i builder = HPyListBuilder_i_New(ctx, 5); + HPyListBuilder_i_Set(ctx, builder, 0, 42); + ... + HPy h_list = HPyListBuilder_i_Build(ctx, builder); + +And similar for building tuples or bytes