[pypy-svn] r32613 - in pypy/dist/pypy/rpython: . lltypesystem memory memory/test
mwh at codespeak.net
mwh at codespeak.net
Sun Sep 24 01:06:36 CEST 2006
Author: mwh
Date: Sun Sep 24 01:06:32 2006
New Revision: 32613
Modified:
pypy/dist/pypy/rpython/llinterp.py
pypy/dist/pypy/rpython/lltypesystem/llmemory.py
pypy/dist/pypy/rpython/memory/gctransform.py
pypy/dist/pypy/rpython/memory/test/test_gctransform.py
Log:
so this started out with an attempt to make it possible to llinterp the output
of the refcountinggctransformer.
along the way i:
* implemented raw_memclear for llinterped objects far more thoroughly
* changed the refcountinggctransformer to only rely on an implementation
of raw_malloc from the backend
* found out once again that refcounting builds take ages and produce slow
binaries.
it would be nice if someone could read op_gc_call_rtti_destructor and check it
for sanity
Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py (original)
+++ pypy/dist/pypy/rpython/llinterp.py Sun Sep 24 01:06:32 2006
@@ -632,7 +632,9 @@
gc.collect()
def op_gc_free(self, addr):
- raise NotImplementedError("gc_free")
+ # what can you do?
+ pass
+ #raise NotImplementedError("gc_free")
def op_gc_fetch_exception(self):
raise NotImplementedError("gc_fetch_exception")
@@ -641,7 +643,10 @@
raise NotImplementedError("gc_restore_exception")
def op_gc_call_rtti_destructor(self, rtti, addr):
- raise NotImplementedError("gc_call_rtti_destructor")
+ if hasattr(rtti._obj, 'destructor_funcptr'):
+ d = rtti._obj.destructor_funcptr
+ ob = addr.get()
+ return self.op_direct_call(d, ob)
def op_gc_deallocate(self, TYPE, addr):
raise NotImplementedError("gc_deallocate")
Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llmemory.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py Sun Sep 24 01:06:32 2006
@@ -24,6 +24,8 @@
def raw_malloc(self, rest):
raise NotImplementedError("raw_malloc(%r, %r)" % (self, rest))
+ def raw_memclear(self, adr):
+ raise NotImplementedError("raw_memclear(%r, %r)" % (self, adr))
class ItemOffset(AddressOffset):
@@ -64,6 +66,25 @@
array_adr = cast_ptr_to_adr(p)
return array_adr + ArrayItemsOffset(T)
+ def raw_memclear(self, adr):
+ if (isinstance(self.TYPE, lltype.ContainerType) and self.repeat == 1):
+ from pypy.rpython.rctypes.rmodel import reccopy
+ fresh = lltype.malloc(self.TYPE, flavor='raw', zero=True)
+ reccopy(fresh, adr.get())
+ else:
+ assert adr.offset is not None
+ if isinstance(adr.offset, ArrayItemsOffset):
+ array = adr.ob
+ elif isinstance(adr.offset, CompositeOffset):
+ array = (adr + -adr.offset.offsets[-1]).get()
+ if isinstance(self.TYPE, lltype.ContainerType):
+ fresh = lltype.malloc(self.TYPE, flavor='raw', zero=True)
+ for i in range(self.repeat):
+ reccopy(fresh, array[i])
+ else:
+ for i in range(self.repeat):
+ array[i] = self.TYPE._defl()
+
class FieldOffset(AddressOffset):
@@ -86,6 +107,22 @@
assert rest
return rest[0].raw_malloc(rest[1:], parenttype=parenttype or self.TYPE)
+ def raw_memclear(self, adr):
+ if self.fldname != self.TYPE._arrayfld:
+ return AddressOffset.raw_memclear(adr) # for the error msg
+ structptr = adr.get()
+ for name in self.TYPE._names[:-1]:
+ FIELDTYPE = getattr(self.TYPE, name)
+ if isinstance(FIELDTYPE, lltype.ContainerType):
+ fresh = lltype.malloc(FIELDTYPE, raw=True, zero=True)
+ from pypy.rpython.rctypes.rmodel import reccopy
+ fresh = lltype.malloc(self.TYPE, flavor='raw', zero=True)
+ reccopy(fresh, getattr(structptr, name)._obj)
+ else:
+ setattr(structptr, name, FIELDTYPE._defl())
+
+
+
class CompositeOffset(AddressOffset):
@@ -125,6 +162,12 @@
def raw_malloc(self, rest):
return self.offsets[0].raw_malloc(self.offsets[1:] + rest)
+ def raw_memclear(self, adr):
+ for o in self.offsets[:-1]:
+ o.raw_memclear(adr)
+ adr += o
+ o.raw_memclear(adr)
+
class ArrayItemsOffset(AddressOffset):
@@ -153,6 +196,10 @@
immortal = self.TYPE._gckind == 'raw')
return cast_ptr_to_adr(p)
+ def raw_memclear(self, adr):
+ # should really zero out the length field, but we can't
+ pass
+
class ArrayLengthOffset(AddressOffset):
@@ -191,6 +238,9 @@
headerptr = self.gcheaderbuilder.new_header(gcobjadr.get())
return cast_ptr_to_adr(headerptr)
+ def raw_memclear(self, adr):
+ headerptr = adr.get()
+ sizeof(lltype.typeOf(headerptr).TO).raw_memclear(cast_ptr_to_adr(headerptr))
class GCHeaderAntiOffset(AddressOffset):
def __init__(self, gcheaderbuilder):
@@ -560,15 +610,10 @@
return size
def raw_memclear(adr, size):
- # hack hack hack
- # stab stab stab
- assert (adr.offset is None or
- (isinstance(adr.offset, ArrayItemsOffset)
- and isinstance(lltype.typeOf(adr.ob).TO, lltype.FixedSizeArray)))
- TYPE = lltype.typeOf(adr.ob)
- fresh = lltype.malloc(TYPE.TO, zero=True, flavor='raw')
- from pypy.rpython.rctypes.rmodel import reccopy
- reccopy(fresh, adr.ob)
+ if not isinstance(size, AddressOffset):
+ raise NotImplementedError(size)
+ assert lltype.typeOf(adr) == Address
+ size.raw_memclear(adr)
def raw_memcopy(source, dest, size):
source = source.get()
Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py Sun Sep 24 01:06:32 2006
@@ -21,7 +21,9 @@
from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.rpython.rtyper import LowLevelOpList
-import sets, os
+from pypy.rpython.rbuiltin import gen_cast
+from pypy.rpython.rarithmetic import ovfcheck
+import sets, os, sys
def var_ispyobj(var):
if hasattr(var, 'concretetype'):
@@ -425,27 +427,51 @@
gc_header_offset = self.gcheaderbuilder.size_gc_header
self.deallocator_graphs_needing_transforming = []
# create incref graph
+ HDRPTR = lltype.Ptr(self.HDR)
def ll_incref(adr):
if adr:
- gcheader = adr - gc_header_offset
- gcheader.signed[0] = gcheader.signed[0] + 1
+ gcheader = llmemory.cast_adr_to_ptr(adr - gc_header_offset, HDRPTR)
+ gcheader.refcount = gcheader.refcount + 1
def ll_decref(adr, dealloc):
if adr:
- gcheader = adr - gc_header_offset
- refcount = gcheader.signed[0] - 1
- gcheader.signed[0] = refcount
+ gcheader = llmemory.cast_adr_to_ptr(adr - gc_header_offset, HDRPTR)
+ refcount = gcheader.refcount - 1
+ gcheader.refcount = refcount
if refcount == 0:
dealloc(adr)
def ll_decref_simple(adr):
if adr:
- gcheader = adr - gc_header_offset
- refcount = gcheader.signed[0] - 1
+ gcheader = llmemory.cast_adr_to_ptr(adr - gc_header_offset, HDRPTR)
+ refcount = gcheader.refcount - 1
if refcount == 0:
llop.gc_free(lltype.Void, adr)
else:
- gcheader.signed[0] = refcount
+ gcheader.refcount = refcount
def ll_no_pointer_dealloc(adr):
llop.gc_free(lltype.Void, adr)
+
+ def ll_malloc_fixedsize(size):
+ size = gc_header_offset + size
+ result = lladdress.raw_malloc(size)
+ lladdress.raw_memclear(result, size)
+ result += gc_header_offset
+ return result
+ def ll_malloc_varsize_no_length(length, size, itemsize):
+ try:
+ fixsize = gc_header_offset + size
+ varsize = ovfcheck(itemsize * length)
+ tot_size = ovfcheck(fixsize + varsize)
+ except OverflowError:
+ raise MemoryError
+ result = lladdress.raw_malloc(tot_size)
+ lladdress.raw_memclear(result, tot_size)
+ result += gc_header_offset
+ return result
+ def ll_malloc_varsize(length, size, itemsize, lengthoffset):
+ result = ll_malloc_varsize_no_length(length, size, itemsize)
+ (result + lengthoffset).signed[0] = length
+ return result
+
if self.translator:
self.increfptr = self.inittime_helper(
ll_incref, [llmemory.Address], lltype.Void)
@@ -456,6 +482,12 @@
ll_decref_simple, [llmemory.Address], lltype.Void)
self.no_pointer_dealloc_ptr = self.inittime_helper(
ll_no_pointer_dealloc, [llmemory.Address], lltype.Void)
+ self.malloc_fixedsize_ptr = self.inittime_helper(
+ ll_malloc_fixedsize, [lltype.Signed], llmemory.Address)
+ self.malloc_varsize_no_length_ptr = self.inittime_helper(
+ ll_malloc_varsize_no_length, [lltype.Signed]*3, llmemory.Address)
+ self.malloc_varsize_ptr = self.inittime_helper(
+ ll_malloc_varsize, [lltype.Signed]*4, llmemory.Address)
self.mixlevelannotator.finish() # for now
# cache graphs:
self.decref_funcptrs = {}
@@ -526,12 +558,63 @@
result.extend(self.pop_alive(oldval))
return result
-## -- maybe add this for tests and for consistency --
-## def consider_constant(self, TYPE, value):
-## p = value._as_ptr()
-## if not self.gcheaderbuilder.get_header(p):
-## hdr = new_header(p)
-## hdr.refcount = sys.maxint // 2
+ def replace_malloc(self, op, livevars, block):
+ TYPE = op.result.concretetype.TO
+ assert not TYPE._is_varsize()
+ c_size = Constant(llmemory.sizeof(TYPE), lltype.Signed)
+ ops = []
+ v_raw = varoftype(llmemory.Address)
+ return [SpaceOperation("direct_call",
+ [self.malloc_fixedsize_ptr, c_size],
+ v_raw),
+ SpaceOperation("cast_adr_to_ptr",
+ [v_raw],
+ op.result)]
+
+ def replace_malloc_varsize(self, op, livevars, block):
+ def intconst(c): return Constant(c, lltype.Signed)
+
+ TYPE = op.result.concretetype.TO
+ assert TYPE._is_varsize()
+
+ c_const_size = intconst(llmemory.sizeof(TYPE, 0))
+ if isinstance(TYPE, lltype.Struct):
+ ARRAY = TYPE._flds[TYPE._arrayfld]
+ else:
+ ARRAY = TYPE
+ assert isinstance(ARRAY, lltype.Array)
+ c_item_size = intconst(llmemory.sizeof(ARRAY.OF))
+
+ ops = []
+ v_raw = varoftype(llmemory.Address)
+ if ARRAY._hints.get("nolength", False):
+ ops.append(
+ SpaceOperation("direct_call",
+ [self.malloc_varsize_no_length_ptr, op.args[-1],
+ c_const_size, c_item_size],
+ v_raw))
+ else:
+ if isinstance(TYPE, lltype.Struct):
+ offset_to_length = llmemory.FieldOffset(TYPE, TYPE._arrayfld) + llmemory.ArrayLengthOffset(ARRAY)
+ else:
+ offset_to_length = llmemory.ArrayLengthOffset(ARRAY)
+ ops.append(
+ SpaceOperation("direct_call",
+ [self.malloc_varsize_ptr, op.args[-1],
+ c_const_size, c_item_size, intconst(offset_to_length)],
+ v_raw))
+
+ ops.append(SpaceOperation("cast_adr_to_ptr", [v_raw], op.result))
+ return ops
+
+ def consider_constant(self, TYPE, value):
+ if value is not lltype.top_container(value):
+ return
+ if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)):
+ p = value._as_ptr()
+ if not self.gcheaderbuilder.get_header(p):
+ hdr = self.gcheaderbuilder.new_header(p)
+ hdr.refcount = sys.maxint // 2
def static_deallocation_funcptr_for_type(self, TYPE):
if TYPE in self.static_deallocator_funcptrs:
@@ -559,13 +642,13 @@
exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE)
try:
v = cast_adr_to_ptr(addr, PTR_TYPE)
- gcheader = addr - gc_header_offset
+ gcheader = cast_adr_to_ptr(addr - gc_header_offset, HDRPTR)
# refcount is at zero, temporarily bump it to 1:
- gcheader.signed[0] = 1
+ gcheader.refcount = 1
destr_v = cast_pointer(DESTR_ARG, v)
ll_call_destructor(destrptr, destr_v)
- refcount = gcheader.signed[0] - 1
- gcheader.signed[0] = refcount
+ refcount = gcheader.refcount - 1
+ gcheader.refcount = refcount
if refcount == 0:
%s
llop.gc_free(lltype.Void, addr)
@@ -591,7 +674,8 @@
'PTR_TYPE': lltype.Ptr(TYPE),
'DESTR_ARG': DESTR_ARG,
'EXC_INSTANCE_TYPE': self.translator.rtyper.exceptiondata.lltype_of_exception_value,
- 'll_call_destructor': ll_call_destructor}
+ 'll_call_destructor': ll_call_destructor,
+ 'HDRPTR':lltype.Ptr(self.HDR)}
exec src in d
this = d['ll_deallocator']
fptr = self.annotate_helper(this, [llmemory.Address], lltype.Void)
@@ -620,11 +704,11 @@
gc_header_offset = self.gcheaderbuilder.size_gc_header
def ll_dealloc(addr):
# bump refcount to 1
- gcheader = addr - gc_header_offset
- gcheader.signed[0] = 1
+ gcheader = llmemory.cast_adr_to_ptr(addr - gc_header_offset, lltype.Ptr(self.HDR))
+ gcheader.refcount = 1
v = llmemory.cast_adr_to_ptr(addr, QUERY_ARG_TYPE)
rtti = queryptr(v)
- gcheader.signed[0] = 0
+ gcheader.refcount = 0
llop.gc_call_rtti_destructor(lltype.Void, rtti, addr)
fptr = self.annotate_helper(ll_dealloc, [llmemory.Address], lltype.Void)
self.dynamic_deallocator_funcptrs[TYPE] = fptr
Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original)
+++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Sun Sep 24 01:06:32 2006
@@ -69,9 +69,9 @@
def rtype_and_transform(func, inputtypes, transformcls, specialize=True, check=True):
t = rtype(func, inputtypes, specialize)
+ transformer = transformcls(t)
etrafo = ExceptionTransformer(t)
etrafo.transform_completely()
- transformer = transformcls(t)
graphs_borrowed = {}
for graph in t.graphs:
graphs_borrowed[graph] = transformer.transform_graph(graph)
@@ -586,7 +586,8 @@
t, transformer = rtype_and_transform(
f, [int], gctransform.RefcountingGCTransformer, check=False)
fgraph = graphof(t, f)
- TYPE = fgraph.startblock.operations[0].result.concretetype.TO
+ s_instance = t.annotator.bookkeeper.valueoftype(A)
+ TYPE = t.rtyper.getrepr(s_instance).lowleveltype.TO
p = transformer.dynamic_deallocation_funcptr_for_type(TYPE)
t.rtyper.specialize_more_blocks()
@@ -722,3 +723,99 @@
res = llinterp.eval_graph(entrygraph, [ll_argv])
assert ''.join(res.chars) == "2"
+
+def llinterpreter_for_refcounted_graph(f, args_s):
+ from pypy.rpython.llinterp import LLInterpreter
+ from pypy.translator.c.genc import CStandaloneBuilder
+ from pypy.translator.c import gc
+
+ t = rtype(f, args_s)
+ cbuild = CStandaloneBuilder(t, f, gc.RefcountingGcPolicy)
+ db = cbuild.generate_graphs_for_llinterp()
+ graph = cbuild.getentrypointptr()._obj.graph
+ llinterp = LLInterpreter(t.rtyper)
+ if conftest.option.view:
+ t.view()
+ return llinterp, graph
+ res = llinterp.eval_graph(graph, [0])
+ assert res == f(0)
+ res = llinterp.eval_graph(graph, [1])
+ assert res == f(1)
+
+
+def test_llinterp_refcounted_graph():
+ from pypy.annotation.model import SomeInteger
+
+ class C:
+ pass
+ c = C()
+ c.x = 1
+ def g(x):
+ if x:
+ return c
+ else:
+ d = C()
+ d.x = 2
+ return d
+ def f(x):
+ return g(x).x
+
+ llinterp, graph = llinterpreter_for_refcounted_graph(f, [SomeInteger()])
+
+ res = llinterp.eval_graph(graph, [0])
+ assert res == f(0)
+ res = llinterp.eval_graph(graph, [1])
+ assert res == f(1)
+
+def test_llinterp_refcounted_graph_varsize():
+ from pypy.annotation.model import SomeInteger
+
+ def f(x):
+ r = []
+ for i in range(x):
+ if i % 2:
+ r.append(x)
+ return len(r)
+
+
+ llinterp, graph = llinterpreter_for_refcounted_graph(f, [SomeInteger()])
+
+ res = llinterp.eval_graph(graph, [0])
+ assert res == f(0)
+ res = llinterp.eval_graph(graph, [10])
+ assert res == f(10)
+
+def test_llinterp_refcounted_graph_with_del():
+ from pypy.annotation.model import SomeInteger
+
+ class D:
+ pass
+
+ delcounter = D()
+ delcounter.dels = 0
+
+ class C:
+ def __del__(self):
+ delcounter.dels += 1
+ c = C()
+ c.x = 1
+ def h(x):
+ if x:
+ return c
+ else:
+ d = C()
+ d.x = 2
+ return d
+ def g(x):
+ return h(x).x
+ def f(x):
+ r = g(x)
+ return r + delcounter.dels
+
+ llinterp, graph = llinterpreter_for_refcounted_graph(f, [SomeInteger()])
+
+ res = llinterp.eval_graph(graph, [1])
+ assert res == 1
+ res = llinterp.eval_graph(graph, [0])
+ assert res == 3
+
More information about the Pypy-commit
mailing list