[pypy-svn] r51690 - in pypy/branch/gc-in-genc/pypy: rpython/lltypesystem rpython/memory/gctransform translator/c
arigo at codespeak.net
arigo at codespeak.net
Wed Feb 20 15:50:51 CET 2008
Author: arigo
Date: Wed Feb 20 15:50:49 2008
New Revision: 51690
Modified:
pypy/branch/gc-in-genc/pypy/rpython/lltypesystem/llmemory.py
pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/framework.py
pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/refcounting.py
pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/transform.py
pypy/branch/gc-in-genc/pypy/translator/c/database.py
pypy/branch/gc-in-genc/pypy/translator/c/funcgen.py
pypy/branch/gc-in-genc/pypy/translator/c/gc.py
pypy/branch/gc-in-genc/pypy/translator/c/node.py
Log:
In-progress. The plan is to ask the GC transformer to turn GC types
into raw types with extra fields for the headers, and GC objects into
raw objects. I hope this is not going to make the "translate.py" memory
requirements go through the roof again.
Modified: pypy/branch/gc-in-genc/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/rpython/lltypesystem/llmemory.py (original)
+++ pypy/branch/gc-in-genc/pypy/rpython/lltypesystem/llmemory.py Wed Feb 20 15:50:49 2008
@@ -103,7 +103,7 @@
while True:
src = cast_adr_to_ptr(srcadr, PTR)
dst = cast_adr_to_ptr(dstadr, PTR)
- _reccopy(src, dst)
+ reccopy(src, dst)
repeat -= 1
if repeat <= 0:
break
@@ -162,7 +162,7 @@
PTR = lltype.Ptr(self.TYPE)
src = cast_adr_to_ptr(srcadr, PTR)
dst = cast_adr_to_ptr(dstadr, PTR)
- _reccopy(src, dst)
+ reccopy(src, dst)
class CompositeOffset(AddressOffset):
@@ -285,7 +285,7 @@
return cast_ptr_to_adr(headerptr)
def raw_memcopy(self, srcadr, dstadr):
- _reccopy(srcadr.ptr, dstadr.ptr)
+ reccopy(srcadr.ptr, dstadr.ptr)
class GCHeaderAntiOffset(AddressOffset):
def __init__(self, gcheaderbuilder):
@@ -698,7 +698,7 @@
return lltype.cast_pointer(EXPECTED_TYPE, ptr)
-def _reccopy(source, dest):
+def reccopy(source, dest):
# copy recursively a structure or array onto another.
T = lltype.typeOf(source).TO
assert T == lltype.typeOf(dest).TO
@@ -709,7 +709,7 @@
if isinstance(ITEMTYPE, lltype.ContainerType):
subsrc = source._obj.getitem(i)._as_ptr()
subdst = dest._obj.getitem(i)._as_ptr()
- _reccopy(subsrc, subdst)
+ reccopy(subsrc, subdst)
else:
# this is a hack XXX de-hack this
llvalue = source._obj.getitem(i, uninitialized_ok=True)
@@ -720,7 +720,7 @@
if isinstance(FIELDTYPE, lltype.ContainerType):
subsrc = source._obj._getattr(name)._as_ptr()
subdst = dest._obj._getattr(name)._as_ptr()
- _reccopy(subsrc, subdst)
+ reccopy(subsrc, subdst)
else:
# this is a hack XXX de-hack this
llvalue = source._obj._getattr(name, uninitialized_ok=True)
Modified: pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/framework.py Wed Feb 20 15:50:49 2008
@@ -332,11 +332,7 @@
self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc)
self.needs_zero_gc_pointers = GCClass.needs_zero_gc_pointers
- HDR = self._gc_HDR = self.gcdata.gc.gcheaderbuilder.HDR
- self._gc_fields = fields = []
- for fldname in HDR._names:
- FLDTYPE = getattr(HDR, fldname)
- fields.append(('_' + fldname, FLDTYPE))
+ self.HDR = self.gcdata.gc.gcheaderbuilder.HDR
def build_root_walker(self):
return ShadowStackRootWalker(self)
@@ -351,12 +347,9 @@
def finalizer_funcptr_for_type(self, TYPE):
return self.layoutbuilder.finalizer_funcptr_for_type(TYPE)
- def gc_fields(self):
- return self._gc_fields
-
def gc_field_values_for(self, obj):
hdr = self.gcdata.gc.gcheaderbuilder.header_of_object(obj)
- HDR = self._gc_HDR
+ HDR = self.HDR
return [getattr(hdr, fldname) for fldname in HDR._names]
def finish_tables(self):
Modified: pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/refcounting.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/refcounting.py (original)
+++ pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/refcounting.py Wed Feb 20 15:50:49 2008
@@ -174,14 +174,12 @@
lltype.typeOf(dealloc_fptr), dealloc_fptr)
hop.genop("direct_call", [cdealloc_fptr, v_addr])
- 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 build_gc_header(self, p):
+ hdr = self.gcheaderbuilder.get_header(p)
+ if not hdr:
+ hdr = self.gcheaderbuilder.new_header(p)
+ hdr.refcount = sys.maxint // 2
+ return hdr
def static_deallocation_funcptr_for_type(self, TYPE):
if TYPE in self.static_deallocator_funcptrs:
Modified: pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/transform.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/transform.py (original)
+++ pypy/branch/gc-in-genc/pypy/rpython/memory/gctransform/transform.py Wed Feb 20 15:50:49 2008
@@ -486,6 +486,9 @@
self.stack_malloc_fixedsize_ptr = self.inittime_helper(
ll_stack_malloc_fixedsize, [lltype.Signed], llmemory.Address)
+ self.raw_type_cache = {}
+ self.raw_obj_cache = {}
+
def gct_malloc(self, hop):
TYPE = hop.spaceop.result.concretetype.TO
assert not TYPE._is_varsize()
@@ -611,3 +614,119 @@
hop.genop('raw_free', [v])
else:
assert False, "%s has no support for free with flavor %r" % (self, flavor)
+
+ # __________ data types and prebuilt objects __________
+ #
+ # The logic below converts GC types to non-GC types, and prebuilt GC
+ # objects to corresponding prebuilt non-GC objects. It is not recursive
+ # in the sense that if a GcStruct contains a GC pointer, its convertion
+ # as a raw Struct still contains a GC pointer.
+
+ def needs_gcheader(self, T):
+ assert isinstance(T, lltype.ContainerType) and T._gckind == 'gc'
+ if isinstance(T, lltype.GcStruct):
+ if T._first_struct() != (None, None):
+ return False # gcheader already in the first field
+ return True
+
+ def get_raw_type_for_gc_type(self, T):
+ """For a 'gc'-kind type T, returns a corresponding 'raw'-kind type
+ which should be used by the backends.
+ """
+ try:
+ return self.raw_type_cache[T]
+ except KeyError:
+ if isinstance(T, (lltype.GcStruct, lltype.GcArray)):
+ # default logic: insert a header of type self.HDR
+ rawfields = []
+ if self.needs_gcheader(T):
+ rawfields.append(('gc__hdr', self.HDR)) # xxx name clash?
+ if isinstance(T, lltype.GcStruct):
+ for name in T._names:
+ FIELD = T._flds[name]
+ if (isinstance(FIELD, lltype.ContainerType)
+ and FIELD._gckind == 'gc'):
+ FIELD = self.get_raw_type_for_gc_type(FIELD)
+ rawfields.append((name, FIELD))
+ else:
+ rawfields.append(('array', lltype.Array(T.OF)))
+ kwds = {'hints': {'raw_for_gc': True}}
+ RAWT = lltype.Struct(T._name, *rawfields, **kwds)
+ else:
+ raise TypeError("not supported by %s: %r" % (
+ self.__class__.__name__, T))
+ self.raw_type_cache[T] = RAWT
+ return RAWT
+
+ def transform_prebuilt_gc_object(self, container):
+ try:
+ return self.raw_obj_cache[container]
+ except KeyError:
+ pass
+ # if 'container' is inlined in a larger object, convert that
+ # and get a reference to the corresponding part in the convertion
+ parent, parentindex = lltype.parentlink(container)
+ if parent is not None:
+ rawparent = self.transform_prebuilt_gc_object(parent)
+ if isinstance(parentindex, str):
+ result = rawparent._getattr(parentindex)
+ else:
+ result = rawparent.getitem(parentindex)
+ else:
+ T = lltype.typeOf(container)
+ if isinstance(T, (lltype.GcStruct, lltype.GcArray)):
+ # allocate the equivalent raw structure
+ RAWT = self.get_raw_type_for_gc_type(T)
+ if T._is_varsize():
+ length = container.getlength()
+ else:
+ length = None
+ result = lltype.malloc(RAWT, length, immortal=True)._as_obj()
+ # copy the header and structure fields or array items in place
+ self._copy_fields_from_gc_to_raw(container, result)
+ else:
+ raise TypeError("not supported by %s: %r" % (
+ self.__class__.__name__, T))
+ self.raw_obj_cache[container] = result
+ return result
+
+ def _copy_fields_from_gc_to_raw(self, container, raw):
+ T = lltype.typeOf(container)
+ if self.needs_gcheader(T):
+ hdr = self.build_gc_header(lltype.top_container(container))
+ llmemory.reccopy(hdr, raw.gc__hdr._as_ptr())
+ if isinstance(T, lltype.GcStruct):
+ for name in T._names:
+ FIELD = T._flds[name]
+ src = container._getattr(name)
+ if isinstance(FIELD, lltype.ContainerType):
+ dst = raw._getattr(name)
+ if FIELD._gckind == 'gc':
+ # an inlined GC substructure: recursively convert it
+ self._copy_fields_from_gc_to_raw(src, dst)
+ else:
+ # an inlined raw substructure: copy it over
+ llmemory.reccopy(src._as_ptr(), dst._as_ptr())
+ else:
+ # a non-container value
+ setattr(raw, name, src)
+ else:
+ assert isinstance(T, lltype.GcArray)
+ dst = raw.array
+ assert dst.getlength() == container.getlength()
+ if isinstance(T.OF, lltype.ContainerType):
+ # array of containers - reccopy each item
+ for i in range(container.getlength()):
+ llmemory.reccopy(container.getitem(i)._as_ptr(),
+ dst.getitem(i)._as_ptr())
+ else:
+ # array of non-containers - copy each item
+ for i in range(container.getlength()):
+ dst.setitem(i, container.getitem(i))
+
+ def consider_constant(self, T, container):
+ if not T._hints.get('raw_for_gc', False):
+ self.consider_constant_nongc(T, container)
+
+ def consider_constant_nongc(self, T, container):
+ "To be overridden."
Modified: pypy/branch/gc-in-genc/pypy/translator/c/database.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/translator/c/database.py (original)
+++ pypy/branch/gc-in-genc/pypy/translator/c/database.py Wed Feb 20 15:50:49 2008
@@ -22,9 +22,8 @@
# ____________________________________________________________
class LowLevelDatabase(object):
- gctransformer = None
- def __init__(self, translator=None, standalone=False,
+ def __init__(self, translator, standalone=False,
gcpolicyclass=None,
stacklesstransformer=None,
thread_enabled=False,
@@ -54,12 +53,8 @@
self.late_initializations = []
self.namespace = CNameManager()
- if translator is None or translator.rtyper is None:
- self.exctransformer = None
- else:
- self.exctransformer = translator.getexceptiontransformer()
- if translator is not None:
- self.gctransformer = self.gcpolicy.transformerclass(translator)
+ self.exctransformer = translator.getexceptiontransformer()
+ self.gctransformer = self.gcpolicy.transformerclass(translator)
self.completed = False
self.instrument_ncounter = 0
@@ -71,8 +66,16 @@
else:
key = T, varlength
try:
- node = self.structdefnodes[key]
+ return self.structdefnodes[key]
except KeyError:
+ pass
+ if not isinstance(T, ContainerType):
+ raise TypeError("ContainerType expected, got %r" % (T,))
+ if T._gckind == 'gc':
+ RAWT = self.gctransformer.get_raw_type_for_gc_type(T)
+ assert RAWT._gckind == 'raw'
+ node = self.gettypedefnode(RAWT, varlength)
+ else:
if isinstance(T, Struct):
if isinstance(T, FixedSizeArray):
node = FixedSizeArrayDefNode(self, T)
@@ -83,15 +86,13 @@
node = BareBoneArrayDefNode(self, T, varlength)
else:
node = ArrayDefNode(self, T, varlength)
- elif isinstance(T, OpaqueType) and T.hints.get("render_structure", False):
+ elif (isinstance(T, OpaqueType) and
+ T.hints.get("render_structure", False)):
node = ExtTypeOpaqueDefNode(self, T)
- elif T == WeakRef:
- REALT = self.gcpolicy.get_real_weakref_type()
- node = self.gettypedefnode(REALT)
else:
raise NoCorrespondingNode("don't know about %r" % (T,))
- self.structdefnodes[key] = node
self.pendingsetupnodes.append(node)
+ self.structdefnodes[key] = node
return node
def gettype(self, T, varlength=1, who_asks=None, argnames=[]):
@@ -144,21 +145,24 @@
else:
raise Exception("don't know about type %r" % (T,))
- def getcontainernode(self, container, _dont_write_c_code=True, **buildkwds):
+ def getcontainernode(self, container): #, **buildkwds):
try:
node = self.containernodes[container]
except KeyError:
T = typeOf(container)
+ if T._gckind == 'gc':
+ gct = self.gctransformer
+ rawcontainer = gct.transform_prebuilt_gc_object(container)
+ node = self.getcontainernode(rawcontainer)
+ self.containernodes[container] = node
+ return node
+
if isinstance(T, (lltype.Array, lltype.Struct)):
- if hasattr(self.gctransformer, 'consider_constant'):
- self.gctransformer.consider_constant(T, container)
+ self.gctransformer.consider_constant(T, container)
+
nodefactory = ContainerNodeFactory[T.__class__]
- node = nodefactory(self, T, container, **buildkwds)
+ node = nodefactory(self, T, container) #, **buildkwds)
self.containernodes[container] = node
- # _dont_write_c_code should only be False for a hack in
- # weakrefnode_factory()
- if not _dont_write_c_code:
- return node
kind = getattr(node, 'nodekind', '?')
self.containerstats[kind] = self.containerstats.get(kind, 0) + 1
self.containerlist.append(node)
@@ -278,15 +282,13 @@
# steps with calls to the next 'finish' function from the following
# list:
finish_callbacks = []
- if self.gctransformer:
- finish_callbacks.append(('GC transformer: finished helpers',
- self.gctransformer.finish_helpers))
+ finish_callbacks.append(('GC transformer: finished helpers',
+ self.gctransformer.finish_helpers))
if self.stacklesstransformer:
finish_callbacks.append(('Stackless transformer: finished',
self.stacklesstransformer.finish))
- if self.gctransformer:
- finish_callbacks.append(('GC transformer: finished tables',
- self.gctransformer.finish_tables))
+ finish_callbacks.append(('GC transformer: finished tables',
+ self.gctransformer.finish_tables))
def add_dependencies(newdependencies):
for value in newdependencies:
Modified: pypy/branch/gc-in-genc/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/gc-in-genc/pypy/translator/c/funcgen.py Wed Feb 20 15:50:49 2008
@@ -47,11 +47,9 @@
if db.stacklesstransformer:
db.stacklesstransformer.transform_graph(graph)
# apply the exception transformation
- if self.db.exctransformer:
- self.db.exctransformer.create_exception_handling(self.graph)
+ self.db.exctransformer.create_exception_handling(self.graph)
# apply the gc transformation
- if self.db.gctransformer:
- self.db.gctransformer.transform_graph(self.graph)
+ self.db.gctransformer.transform_graph(self.graph)
#self.graph.show()
self.collect_var_and_types()
Modified: pypy/branch/gc-in-genc/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/translator/c/gc.py (original)
+++ pypy/branch/gc-in-genc/pypy/translator/c/gc.py Wed Feb 20 15:50:49 2008
@@ -33,9 +33,6 @@
def array_gcheader_initdata(self, defnode):
return self.common_gcheader_initdata(defnode)
- def struct_after_definition(self, defnode):
- return []
-
def gc_libraries(self):
return []
Modified: pypy/branch/gc-in-genc/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/gc-in-genc/pypy/translator/c/node.py (original)
+++ pypy/branch/gc-in-genc/pypy/translator/c/node.py Wed Feb 20 15:50:49 2008
@@ -1,7 +1,7 @@
from __future__ import generators
from pypy.rpython.lltypesystem.lltype import \
Struct, Array, FixedSizeArray, FuncType, PyObjectType, typeOf, \
- GcStruct, GcArray, RttiStruct, ContainerType, \
+ ContainerType, \
parentlink, Ptr, PyObject, Void, OpaqueType, Float, \
RuntimeTypeInfo, getRuntimeTypeInfo, Char, _subarray
from pypy.rpython.lltypesystem import llmemory
@@ -15,29 +15,11 @@
from pypy.translator.c import extfunc
from pypy.translator.tool.cbuild import ExternalCompilationInfo
-def needs_gcheader(T):
- if not isinstance(T, ContainerType):
- return False
- if T._gckind != 'gc':
- return False
- if isinstance(T, GcStruct):
- if T._first_struct() != (None, None):
- return False # gcheader already in the first field
- return True
-
-class defaultproperty(object):
- def __init__(self, fget):
- self.fget = fget
- def __get__(self, obj, cls=None):
- if obj is None:
- return self
- else:
- return self.fget(obj)
-
class StructDefNode:
typetag = 'struct'
def __init__(self, db, STRUCT, varlength=1):
+ assert STRUCT._gckind == 'raw'
self.db = db
self.STRUCT = STRUCT
self.LLTYPE = STRUCT
@@ -51,7 +33,6 @@
with_number = False
if STRUCT._hints.get('union'):
self.typetag = 'union'
- assert STRUCT._gckind == 'raw' # not supported: "GcUnion"
if STRUCT._hints.get('typedef'):
self.typetag = ''
assert STRUCT._hints.get('external')
@@ -77,9 +58,6 @@
db = self.db
STRUCT = self.STRUCT
varlength = self.varlength
- if needs_gcheader(self.STRUCT):
- for fname, T in db.gcpolicy.struct_gcheader_definition(self):
- self.fields.append((fname, db.gettype(T, who_asks=self)))
for name in STRUCT._names:
T = self.c_struct_field_type(name)
if name == STRUCT._arrayfld:
@@ -88,22 +66,6 @@
else:
typename = db.gettype(T, who_asks=self)
self.fields.append((self.c_struct_field_name(name), typename))
- self.gcinfo # force it to be computed
-
- def computegcinfo(self):
- # let the gcpolicy do its own setup
- self.gcinfo = None # unless overwritten below
- rtti = None
- STRUCT = self.STRUCT
- if isinstance(STRUCT, RttiStruct):
- try:
- rtti = getRuntimeTypeInfo(STRUCT)
- except ValueError:
- pass
- if self.varlength == 1:
- self.db.gcpolicy.struct_setup(self, rtti)
- return self.gcinfo
- gcinfo = defaultproperty(computegcinfo)
def gettype(self):
return '%s %s @' % (self.typetag, self.name)
@@ -162,8 +124,6 @@
if is_empty:
yield '\t' + 'char _dummy; /* this struct is empty */'
yield '};'
- for line in self.db.gcpolicy.struct_after_definition(self):
- yield line
def visitor_lines(self, prefix, on_field):
STRUCT = self.STRUCT
@@ -195,12 +155,12 @@
typetag = 'struct'
def __init__(self, db, ARRAY, varlength=1):
+ assert ARRAY._gckind == 'raw'
self.db = db
self.ARRAY = ARRAY
self.LLTYPE = ARRAY
original_varlength = varlength
- self.gcfields = []
-
+
if ARRAY._hints.get('isrpystring'):
varlength += 1 # for the NUL char terminator at the end of the string
self.varlength = varlength
@@ -221,20 +181,8 @@
return # setup() was already called, likely by __init__
db = self.db
ARRAY = self.ARRAY
- self.gcinfo # force it to be computed
- if needs_gcheader(ARRAY):
- for fname, T in db.gcpolicy.array_gcheader_definition(self):
- self.gcfields.append((fname, db.gettype(T, who_asks=self)))
self.itemtypename = db.gettype(ARRAY.OF, who_asks=self)
- def computegcinfo(self):
- # let the gcpolicy do its own setup
- self.gcinfo = None # unless overwritten below
- if self.varlength == 1:
- self.db.gcpolicy.array_setup(self)
- return self.gcinfo
- gcinfo = defaultproperty(computegcinfo)
-
def gettype(self):
return '%s %s @' % (self.typetag, self.name)
@@ -256,10 +204,7 @@
return 'RPyItem(%s, %s)' % (baseexpr, indexexpr)
def definition(self):
- gcpolicy = self.db.gcpolicy
yield 'struct %s {' % self.name
- for fname, typename in self.gcfields:
- yield '\t' + cdecl(typename, fname) + ';'
if not self.ARRAY._hints.get('nolength', False):
yield '\tlong length;'
line = '%s;' % cdecl(self.itemtypename, 'items[%d]'% self.varlength)
@@ -312,7 +257,6 @@
Implemented directly as a C array instead of a struct with an items field.
rffi kind of expects such arrays to be 'bare' C arrays.
"""
- gcinfo = None
name = None
forward_decl = None
@@ -359,7 +303,6 @@
class FixedSizeArrayDefNode:
- gcinfo = None
name = None
typetag = 'struct'
@@ -530,10 +473,6 @@
data = []
- if needs_gcheader(self.T):
- for i, thing in enumerate(self.db.gcpolicy.struct_gcheader_initdata(self)):
- data.append(('gcheader%d'%i, thing))
-
for name in self.T._names:
data.append((name, getattr(self.obj, name)))
@@ -581,13 +520,6 @@
def initializationexpr(self, decoration=''):
defnode = self.db.gettypedefnode(self.T)
yield '{'
- if needs_gcheader(self.T):
- for i, thing in enumerate(self.db.gcpolicy.array_gcheader_initdata(self)):
- lines = generic_initializationexpr(self.db, thing,
- 'gcheader%d'%i,
- '%sgcheader%d' % (decoration, i))
- for line in lines:
- yield line
if self.T._hints.get('nolength', False):
length = ''
else:
@@ -903,23 +835,12 @@
def implementation(self):
return []
-def weakrefnode_factory(db, T, obj):
- assert isinstance(obj, llmemory._wref)
- ptarget = obj._dereference()
- wrapper = db.gcpolicy.convert_weakref_to(ptarget)
- container = wrapper._obj
- obj._converted_weakref = container # hack for genllvm :-/
- return db.getcontainernode(container, _dont_write_c_code=False)
-
ContainerNodeFactory = {
Struct: StructNode,
- GcStruct: StructNode,
Array: ArrayNode,
- GcArray: ArrayNode,
FixedSizeArray: FixedSizeArrayNode,
FuncType: FuncNode,
OpaqueType: opaquenode_factory,
PyObjectType: PyObjectNode,
- llmemory._WeakRefType: weakrefnode_factory,
}
More information about the Pypy-commit
mailing list