[pypy-svn] r28581 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem/test translator/c translator/c/src translator/c/test
arigo at codespeak.net
arigo at codespeak.net
Fri Jun 9 13:30:37 CEST 2006
Author: arigo
Date: Fri Jun 9 13:30:35 2006
New Revision: 28581
Modified:
pypy/dist/pypy/annotation/builtin.py
pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
pypy/dist/pypy/rpython/rbuiltin.py
pypy/dist/pypy/rpython/rcpy.py
pypy/dist/pypy/translator/c/funcgen.py
pypy/dist/pypy/translator/c/src/mem.h
pypy/dist/pypy/translator/c/test/test_genc.py
Log:
(arre, arigo)
Added tp_alloc/tp_free and the corresponding support for lltyping
helpers containing 'malloc(PyObject, flavor='cpy', extra_args=(tp,))'.
Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py (original)
+++ pypy/dist/pypy/annotation/builtin.py Fri Jun 9 13:30:35 2006
@@ -384,24 +384,31 @@
from pypy.annotation.model import SomePtr
from pypy.rpython.lltypesystem import lltype
-def malloc(T, n=None, s_flavor=None):
- assert n is None or (n.knowntype == int or issubclass(n.knowntype, pypy.rpython.rarithmetic.base_int))
- assert T.is_constant()
- if n is not None:
+def malloc(s_T, s_n=None, s_flavor=None, s_extra_args=None):
+ assert (s_n is None or s_n.knowntype == int
+ or issubclass(s_n.knowntype, pypy.rpython.rarithmetic.base_int))
+ assert s_T.is_constant()
+ if s_n is not None:
n = 1
+ else:
+ n = None
if s_flavor is None:
- p = lltype.malloc(T.const, n)
+ p = lltype.malloc(s_T.const, n)
+ r = SomePtr(lltype.typeOf(p))
else:
assert s_flavor.is_constant()
- p = lltype.malloc(T.const, n, s_flavor.const)
- r = SomePtr(lltype.typeOf(p))
+ # not sure how to call malloc() for the example 'p' in the
+ # presence of s_extraargs
+ r = SomePtr(lltype.Ptr(s_T.const))
return r
def free(s_p, s_flavor):
assert s_flavor.is_constant()
- T = s_p.ll_ptrtype.TO
- p = lltype.malloc(T, flavor=s_flavor.const)
- lltype.free(p, flavor=s_flavor.const)
+ # same problem as in malloc(): some flavors are not easy to
+ # malloc-by-example
+ #T = s_p.ll_ptrtype.TO
+ #p = lltype.malloc(T, flavor=s_flavor.const)
+ #lltype.free(p, flavor=s_flavor.const)
def typeOf(s_val):
lltype = annotation_to_lltype(s_val, info="in typeOf(): ")
Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py Fri Jun 9 13:30:35 2006
@@ -19,7 +19,7 @@
w = W_MyTest(21)
return cpy_export(mytest, w)
- fn = compile(f, [])
+ fn = compile(f, [], expected_extra_mallocs=1)
res = fn()
assert type(res).__name__ == 'mytest'
@@ -40,3 +40,29 @@
fn = compile(g, [])
res = fn()
assert res == 42
+
+
+def test_tp_dealloc():
+ import py; py.test.skip("in-progress")
+ class mytest(object):
+ pass
+
+ class A(object):
+ pass
+
+ def f():
+ w = W_MyTest(21)
+ w.a = A()
+ w.a.x = 4
+ return cpy_export(mytest, w)
+
+ def g():
+ obj = f()
+ w = cpy_import(W_MyTest, obj)
+ return w.a.x
+
+ fn = compile(g, [], backendopt=False)
+ res = fn()
+ # the A() should have been deallocated too, otherwise the number
+ # of mallocs doesn't match the number of frees
+ assert res == 4
Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py (original)
+++ pypy/dist/pypy/rpython/rbuiltin.py Fri Jun 9 13:30:35 2006
@@ -160,6 +160,23 @@
return NotImplemented
return llops.convertvar(v, r_from.self_repr, r_to.self_repr)
+def parse_kwds(hop, *argspec_i_r):
+ lst = [i for (i, r) in argspec_i_r if i is not None]
+ lst.sort()
+ if lst != range(hop.nb_args - len(lst), hop.nb_args):
+ raise TyperError("keyword args are expected to be at the end of "
+ "the 'hop' arg list")
+ result = []
+ for i, r in argspec_i_r:
+ if i is not None:
+ if r is None:
+ r = hop.args_r[i]
+ result.append(hop.inputarg(r, arg=i))
+ else:
+ result.append(None)
+ hop.nb_args -= len(lst)
+ return result
+
# ____________________________________________________________
def rtype_builtin_bool(hop):
@@ -297,19 +314,28 @@
BUILTIN_TYPER[object.__init__] = rtype_object__init__
# annotation of low-level types
-def rtype_malloc(hop, i_flavor=None):
+def rtype_malloc(hop, i_flavor=None, i_extra_args=None):
assert hop.args_s[0].is_constant()
vlist = [hop.inputarg(lltype.Void, arg=0)]
opname = 'malloc'
- positional_args = hop.nb_args
- if i_flavor is not None:
- assert i_flavor == hop.nb_args-1
- positional_args -= 1
- vlist.insert(0, hop.inputarg(lltype.Void, arg=i_flavor))
+ v_flavor, v_extra_args = parse_kwds(hop, (i_flavor, lltype.Void),
+ (i_extra_args, None))
+ if v_flavor is not None:
+ vlist.insert(0, v_flavor)
opname = 'flavored_' + opname
- if positional_args == 2:
+ if hop.nb_args == 2:
vlist.append(hop.inputarg(lltype.Signed, arg=1))
opname += '_varsize'
+
+ if v_extra_args is not None:
+ # items of the v_extra_args tuple become additional args to the op
+ from pypy.rpython.rtuple import AbstractTupleRepr
+ r_tup = hop.args_r[i_extra_args]
+ assert isinstance(r_tup, AbstractTupleRepr)
+ for n, r in enumerate(r_tup.items_r):
+ v = r_tup.getitem(hop.llops, v_extra_args, n)
+ vlist.append(v)
+
return hop.genop(opname, vlist, resulttype = hop.r_result.lowleveltype)
def rtype_free(hop, i_flavor):
Modified: pypy/dist/pypy/rpython/rcpy.py
==============================================================================
--- pypy/dist/pypy/rpython/rcpy.py (original)
+++ pypy/dist/pypy/rpython/rcpy.py Fri Jun 9 13:30:35 2006
@@ -64,7 +64,8 @@
PyObjPtr = lltype.Ptr(lltype.PyObject)
-PY_TYPE_OBJECT = lltype.PyStruct(
+PY_TYPE_OBJECT = lltype.PyForwardReference()
+PY_TYPE_OBJECT.become(lltype.PyStruct(
'PyTypeObject',
('head', lltype.PyObject),
('c_ob_size', lltype.Signed),
@@ -87,10 +88,41 @@
('c_tp_setattro', lltype.Signed),
('c_tp_as_buffer', lltype.Signed),
('c_tp_flags', lltype.Signed),
+ ('c_tp_doc', lltype.Signed),
+ ('c_tp_traverse', lltype.Signed),
+ ('c_tp_clear', lltype.Signed),
+ ('c_tp_richcompare',lltype.Signed),
+ ('c_tp_weaklistoffset',lltype.Signed),
+ ('c_tp_iter', lltype.Signed),
+ ('c_tp_iternext', lltype.Signed),
+ ('c_tp_methods', lltype.Signed),
+ ('c_tp_members', lltype.Signed),
+ ('c_tp_getset', lltype.Signed),
+ ('c_tp_base', lltype.Signed),
+ ('c_tp_dict', lltype.Signed),
+ ('c_tp_descr_get', lltype.Signed),
+ ('c_tp_descr_set', lltype.Signed),
+ ('c_tp_dictoffset',lltype.Signed),
+ ('c_tp_init', lltype.Signed),
+ ('c_tp_alloc', lltype.Ptr(lltype.FuncType([lltype.Ptr(PY_TYPE_OBJECT),
+ lltype.Signed],
+ PyObjPtr))),
+ ('c_tp_new', lltype.Signed),
+ ('c_tp_free', lltype.Ptr(lltype.FuncType([llmemory.Address],
+ lltype.Void))),
- hints={'c_name': '_typeobject', 'external': True, 'inline_head': True})
+ hints={'c_name': '_typeobject', 'external': True, 'inline_head': True}))
# XXX should be PyTypeObject but genc inserts 'struct' :-(
+def ll_tp_alloc(tp, itemcount):
+ # XXX pass itemcount too
+ return lltype.malloc(lltype.PyObject, flavor='cpy', extra_args=(tp,))
+
+def ll_tp_free(addr):
+ # hack: don't cast addr to PyObjPtr, otherwise there is an incref/decref
+ # added around the free!
+ lltype.free(addr, flavor='cpy')
+
def build_pytypeobject(r_inst):
typetype = lltype.pyobjectptr(type)
pytypeobj = lltype.malloc(PY_TYPE_OBJECT, flavor='cpy',
@@ -104,4 +136,10 @@
pytypeobj.c_tp_name = lltype.direct_arrayitems(p)
pytypeobj.c_tp_basicsize = llmemory.sizeof(r_inst.lowleveltype.TO)
pytypeobj.c_tp_flags = CDefinedIntSymbolic('Py_TPFLAGS_DEFAULT')
+ pytypeobj.c_tp_alloc = r_inst.rtyper.annotate_helper_fn(
+ ll_tp_alloc,
+ [lltype.Ptr(PY_TYPE_OBJECT), lltype.Signed])
+ pytypeobj.c_tp_free = r_inst.rtyper.annotate_helper_fn(
+ ll_tp_free,
+ [llmemory.Address])
return lltype.cast_pointer(PyObjPtr, pytypeobj)
Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py (original)
+++ pypy/dist/pypy/translator/c/funcgen.py Fri Jun 9 13:30:35 2006
@@ -562,16 +562,16 @@
return "OP_STACK_MALLOC(%s, %s);" % (esize, eresult)
elif flavor == "cpy":
cpytype = self.expr(op.args[2])
- return "%s = PyObject_New(%s, (PyTypeObject *)%s);" % (
- eresult, cdecl(typename, ''), cpytype)
+ return "OP_CPY_MALLOC(%s, %s);" % (cpytype, eresult)
else:
raise NotImplementedError
def OP_FLAVORED_FREE(self, op):
flavor = op.args[0].value
if flavor == "raw":
- return "OP_RAW_FREE(%s, %s)" % (self.expr(op.args[1]),
- self.expr(op.result))
+ return "OP_RAW_FREE(%s)" % (self.expr(op.args[1]),)
+ elif flavor == "cpy":
+ return "OP_CPY_FREE(%s)" % (self.expr(op.args[1]),)
else:
raise NotImplementedError
Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h (original)
+++ pypy/dist/pypy/translator/c/src/mem.h Fri Jun 9 13:30:35 2006
@@ -14,7 +14,7 @@
r = (void*) alloca(size); \
if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memory");\
-#define OP_RAW_FREE(x,r) OP_FREE(x)
+#define OP_RAW_FREE(x) OP_FREE(x)
#define OP_RAW_MEMCOPY(x,y,size,r) memcpy(y,x,size);
/************************************************************/
@@ -119,3 +119,15 @@
#define PUSH_ALIVE(obj)
#endif /* USING_NO_GC */
+
+/************************************************************/
+/* rcpy support */
+
+#define OP_CPY_MALLOC(cpytype, r) { \
+ /* XXX add tp_itemsize later */ \
+ OP_RAW_MALLOC(((PyTypeObject *)cpytype)->tp_basicsize, r); \
+ if (r) { \
+ PyObject_Init((PyObject *)r, (PyTypeObject *)cpytype); \
+ } \
+ }
+#define OP_CPY_FREE(x) OP_RAW_FREE(x)
Modified: pypy/dist/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_genc.py (original)
+++ pypy/dist/pypy/translator/c/test/test_genc.py Fri Jun 9 13:30:35 2006
@@ -31,7 +31,7 @@
return m
def compile(fn, argtypes, view=False, gcpolicy=None, backendopt=True,
- annotatorpolicy=None):
+ annotatorpolicy=None, expected_extra_mallocs=0):
t = TranslationContext()
a = t.buildannotator(policy=annotatorpolicy)
a.build_types(fn, argtypes)
@@ -50,7 +50,7 @@
return compiled_fn(*args, **kwds)
finally:
mallocs, frees = module.malloc_counters()
- assert mallocs == frees
+ assert mallocs - frees == expected_extra_mallocs
return checking_fn
def test_func_as_pyobject():
More information about the Pypy-commit
mailing list