[pypy-svn] r28575 - in pypy/dist/pypy: rpython rpython/lltypesystem rpython/lltypesystem/test translator/c translator/c/src

arigo at codespeak.net arigo at codespeak.net
Fri Jun 9 11:42:42 CEST 2006


Author: arigo
Date: Fri Jun  9 11:42:39 2006
New Revision: 28575

Modified:
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
   pypy/dist/pypy/rpython/objectmodel.py
   pypy/dist/pypy/rpython/rcpy.py
   pypy/dist/pypy/rpython/rtyper.py
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/genc.py
   pypy/dist/pypy/translator/c/node.py
   pypy/dist/pypy/translator/c/primitive.py
   pypy/dist/pypy/translator/c/src/module.h
Log:
(arre, arigo)

Fixed the type objects of the hybrid RPython-CPython objects,
by creating a PyTypeObject structure with lltype.

Added rcpy.cpy_import() to cast from CPython to RPython.

lltype pointer solidity fix.

A convenient CDefinedIntSymbolic.

Wack wack wack until genc produces exactly the correct CPython-friendly
kind of code.  GenC support for the _pyobjheaders of lltype.



Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Fri Jun  9 11:42:39 2006
@@ -752,7 +752,7 @@
         raise TypeError, "%s has no field %r" % (CURTYPE, fieldname)
     if not structptr:
         raise RuntimeError("direct_fieldptr: NULL argument")
-    return _subarray._makeptr(structptr._obj, fieldname)
+    return _subarray._makeptr(structptr._obj, fieldname, structptr._solid)
 
 def direct_arrayitems(arrayptr):
     """Get a pointer to the first item of the array.  The resulting
@@ -765,7 +765,7 @@
         raise TypeError, "direct_arrayitems: not an array"
     if not arrayptr:
         raise RuntimeError("direct_arrayitems: NULL argument")
-    return _subarray._makeptr(arrayptr._obj, 0)
+    return _subarray._makeptr(arrayptr._obj, 0, arrayptr._solid)
 
 def direct_ptradd(ptr, n):
     """Shift a pointer forward or backward by n items.  The pointer must
@@ -776,7 +776,7 @@
     if not isinstance(ptr._obj, _subarray):
         raise TypeError("direct_ptradd: only for direct_arrayitems() ptrs")
     parent, base = parentlink(ptr._obj)
-    return _subarray._makeptr(parent, base + n)
+    return _subarray._makeptr(parent, base + n, ptr._solid)
 
 def _expose(val, solid=False):
     """XXX A nice docstring here"""
@@ -1130,7 +1130,7 @@
         self._parent_type = typeOf(parent)
         self._parent_index = parentindex
         if (isinstance(self._parent_type, Struct)
-            and parentindex == self._parent_type._names[0]
+            and parentindex in (self._parent_type._names[0], 0)
             and self._TYPE._gckind == typeOf(parent)._gckind):
             # keep strong reference to parent, we share the same allocation
             self._keepparent = parent 
@@ -1365,7 +1365,7 @@
         else:
             self._parentstructure().setitem(baseoffset + index, value)
 
-    def _makeptr(parent, baseoffset_or_fieldname):
+    def _makeptr(parent, baseoffset_or_fieldname, solid=False):
         cache = _subarray._cache.setdefault(parent, {})
         try:
             subarray = cache[baseoffset_or_fieldname]
@@ -1380,7 +1380,7 @@
             ARRAYTYPE = FixedSizeArray(ITEMTYPE, 1)
             subarray = _subarray(ARRAYTYPE, parent, baseoffset_or_fieldname)
             cache[baseoffset_or_fieldname] = subarray
-        return _ptr(Ptr(subarray._TYPE), subarray)
+        return _ptr(Ptr(subarray._TYPE), subarray, solid)
     _makeptr = staticmethod(_makeptr)
 
 

Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Fri Jun  9 11:42:39 2006
@@ -485,8 +485,14 @@
                 mallocop = 'flavored_malloc'
                 vlist.insert(0, inputconst(Void, flavor))
                 if flavor == 'cpy':
-                    cpytype = self.classdef._cpy_exported_type_
-                    c = inputconst(Ptr(PyObject), lltype.pyobjectptr(cpytype))
+                    cache = self.rtyper.classdef_to_pytypeobject
+                    try:
+                        pytype = cache[self.classdef]
+                    except KeyError:
+                        from pypy.rpython import rcpy
+                        pytype = rcpy.build_pytypeobject(self)
+                        cache[self.classdef] = pytype
+                    c = inputconst(Ptr(PyObject), pytype)
                     vlist.append(c)
         vptr = llops.genop(mallocop, vlist,
                            resulttype = Ptr(self.object_type))

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 11:42:39 2006
@@ -1,5 +1,5 @@
 from pypy.translator.c.test.test_genc import compile
-from pypy.rpython.rcpy import cpy_export
+from pypy.rpython.rcpy import cpy_export, cpy_import
 
 
 class W_MyTest(object):
@@ -17,8 +17,26 @@
 
     def f():
         w = W_MyTest(21)
-        return cpy_export(w, mytest)
+        return cpy_export(mytest, w)
 
     fn = compile(f, [])
     res = fn()
-    assert type(res).__name__.endswith('mytest')
+    assert type(res).__name__ == 'mytest'
+
+
+def test_cpy_import():
+    class mytest(object):
+        pass
+
+    def f():
+        w = W_MyTest(21)
+        return cpy_export(mytest, w)
+
+    def g():
+        obj = f()
+        w = cpy_import(W_MyTest, obj)
+        return w.double()
+
+    fn = compile(g, [])
+    res = fn()
+    assert res == 42

Modified: pypy/dist/pypy/rpython/objectmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/objectmodel.py	(original)
+++ pypy/dist/pypy/rpython/objectmodel.py	Fri Jun  9 11:42:39 2006
@@ -35,6 +35,19 @@
         from pypy.rpython.lltypesystem import lltype
         return lltype.Signed
 
+class CDefinedIntSymbolic(Symbolic):
+
+    def __init__(self, expr):
+        self.expr = expr
+
+    def annotation(self):
+        from pypy.annotation import model
+        return model.SomeInteger()
+
+    def lltype(self):
+        from pypy.rpython.lltypesystem import lltype
+        return lltype.Signed
+
 
 def instantiate(cls):
     "Create an empty instance of 'cls'."

Modified: pypy/dist/pypy/rpython/rcpy.py
==============================================================================
--- pypy/dist/pypy/rpython/rcpy.py	(original)
+++ pypy/dist/pypy/rpython/rcpy.py	Fri Jun  9 11:42:39 2006
@@ -1,14 +1,19 @@
 from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.objectmodel import CDefinedIntSymbolic
 
 
-def cpy_export(obj, cpytype):
+def cpy_export(cpytype, obj):
+    raise NotImplementedError("only works in translated versions")
+
+def cpy_import(rpytype, obj):
     raise NotImplementedError("only works in translated versions")
 
 
 class Entry(ExtRegistryEntry):
     _about_ = cpy_export
 
-    def compute_result_annotation(self, s_obj, s_cpytype):
+    def compute_result_annotation(self, s_cpytype, s_obj):
         from pypy.annotation.model import SomeObject
         from pypy.annotation.model import SomeInstance
         assert isinstance(s_obj, SomeInstance)
@@ -24,7 +29,79 @@
 
     def specialize_call(self, hop):
         from pypy.rpython.lltypesystem import lltype
-        r_inst = hop.args_r[0]
-        v_inst = hop.inputarg(r_inst, arg=0)
+        s_obj = hop.args_s[1]
+        r_inst = hop.args_r[1]
+        v_inst = hop.inputarg(r_inst, arg=1)
         return hop.genop('cast_pointer', [v_inst],
                          resulttype = lltype.Ptr(lltype.PyObject))
+
+
+class Entry(ExtRegistryEntry):
+    _about_ = cpy_import
+
+    def compute_result_annotation(self, s_rpytype, s_obj):
+        from pypy.annotation.bookkeeper import getbookkeeper
+        from pypy.annotation.model import SomeInstance
+        assert s_rpytype.is_constant()
+        rpytype = s_rpytype.const
+        bk = getbookkeeper()
+        return SomeInstance(bk.getuniqueclassdef(rpytype))
+
+    def specialize_call(self, hop):
+        from pypy.annotation.model import SomeInstance
+        from pypy.rpython.robject import pyobj_repr
+        s_rpytype = hop.args_s[0]
+        assert s_rpytype.is_constant()
+        rpytype = s_rpytype.const
+        classdef = hop.rtyper.annotator.bookkeeper.getuniqueclassdef(rpytype)
+        s_inst = SomeInstance(classdef)
+        r_inst = hop.rtyper.getrepr(s_inst)
+        assert r_inst.lowleveltype.TO._gckind == 'cpy'
+        v_obj = hop.inputarg(pyobj_repr, arg=1)
+        return hop.genop('cast_pointer', [v_obj],
+                         resulttype = r_inst.lowleveltype)
+
+
+PyObjPtr = lltype.Ptr(lltype.PyObject)
+
+PY_TYPE_OBJECT = lltype.PyStruct(
+    'PyTypeObject',
+    ('head',           lltype.PyObject),
+    ('c_ob_size',      lltype.Signed),
+    ('c_tp_name',      lltype.Ptr(lltype.FixedSizeArray(lltype.Char, 1))),
+    ('c_tp_basicsize', lltype.Signed),
+    ('c_tp_itemsize',  lltype.Signed),
+    ('c_tp_dealloc',   lltype.Signed),
+    ('c_tp_print',     lltype.Signed),
+    ('c_tp_getattr',   lltype.Signed),
+    ('c_tp_setattr',   lltype.Signed),   # in
+    ('c_tp_compare',   lltype.Signed),
+    ('c_tp_repr',      lltype.Signed),   # progress
+    ('c_tp_as_number', lltype.Signed),
+    ('c_tp_as_sequence',lltype.Signed),
+    ('c_tp_as_mapping',lltype.Signed),
+    ('c_tp_hash',      lltype.Signed),
+    ('c_tp_call',      lltype.Signed),
+    ('c_tp_str',       lltype.Signed),
+    ('c_tp_getattro',  lltype.Signed),
+    ('c_tp_setattro',  lltype.Signed),
+    ('c_tp_as_buffer', lltype.Signed),
+    ('c_tp_flags',     lltype.Signed),
+
+    hints={'c_name': '_typeobject', 'external': True, 'inline_head': True})
+# XXX should be PyTypeObject but genc inserts 'struct' :-(
+
+def build_pytypeobject(r_inst):
+    typetype = lltype.pyobjectptr(type)
+    pytypeobj = lltype.malloc(PY_TYPE_OBJECT, flavor='cpy',
+                              extra_args=(typetype,))
+    name = r_inst.classdef._cpy_exported_type_.__name__
+    T = lltype.FixedSizeArray(lltype.Char, len(name)+1)
+    p = lltype.malloc(T, immortal=True)
+    for i in range(len(name)):
+        p[i] = name[i]
+    p[len(name)] = '\x00'
+    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')
+    return lltype.cast_pointer(PyObjPtr, pytypeobj)

Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py	(original)
+++ pypy/dist/pypy/rpython/rtyper.py	Fri Jun  9 11:42:39 2006
@@ -60,6 +60,7 @@
         self.pbc_reprs = {}
         self.classes_with_wrapper = {}
         self.wrapper_context = None # or add an extra arg to convertvar?
+        self.classdef_to_pytypeobject = {}
         self.concrete_calltables = {}
         self.class_pbc_attributes = {}
         self.oo_meth_impls = {}

Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Fri Jun  9 11:42:39 2006
@@ -2,13 +2,11 @@
 from pypy.translator.c.support import cdecl
 from pypy.translator.c.node import ContainerNode
 from pypy.rpython.lltypesystem.lltype import \
-     typeOf, Ptr, PyObject, ContainerType, GcArray, GcStruct, \
+     typeOf, Ptr, ContainerType, GcArray, GcStruct, \
      RuntimeTypeInfo, getRuntimeTypeInfo, top_container
 from pypy.rpython.memory import gctransform
 from pypy.rpython.lltypesystem import lltype, llmemory
 
-PyObjPtr = Ptr(PyObject)
-
 class BasicGcPolicy(object):
     requires_stackless = False
     
@@ -63,13 +61,7 @@
 class RefcountingInfo:
     static_deallocator = None
 
-from pypy.rpython.objectmodel import Symbolic
-class REFCOUNT_IMMORTAL(Symbolic):
-    def annotation(self):
-        from pypy.annotation.model import SomeInteger
-        return SomeInteger()
-    def lltype(self):
-        return lltype.Signed
+from pypy.rpython.objectmodel import CDefinedIntSymbolic
 
 class RefcountingGcPolicy(BasicGcPolicy):
     transformerclass = gctransform.RefcountingGCTransformer
@@ -78,7 +70,7 @@
         return [('refcount', lltype.Signed)]
 
     def common_gcheader_initdata(self, defnode):
-        return [REFCOUNT_IMMORTAL()]
+        return [CDefinedIntSymbolic('REFCOUNT_IMMORTAL')]
 
     # for structs
 

Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py	(original)
+++ pypy/dist/pypy/translator/c/genc.py	Fri Jun  9 11:42:39 2006
@@ -1,6 +1,6 @@
 import autopath
 import py
-from pypy.translator.c.node import PyObjectNode, FuncNode
+from pypy.translator.c.node import PyObjectNode, PyObjHeadNode, FuncNode
 from pypy.translator.c.database import LowLevelDatabase
 from pypy.translator.c.extfunc import pre_include_code_lines
 from pypy.translator.gensupp import uniquemodulename, NameManager
@@ -689,10 +689,17 @@
     print >> f
     print >> f, 'static globalobjectdef_t globalobjectdefs[] = {'
     for node in database.globalcontainers():
-        if isinstance(node, PyObjectNode):
+        if isinstance(node, (PyObjectNode, PyObjHeadNode)):
             for target in node.where_to_copy_me:
-                print >> f, '\t{%s, "%s"},' % (target, node.name)
-    print >> f, '\t{ NULL }\t/* Sentinel */'
+                print >> f, '\t{%s, "%s"},' % (target, node.exported_name)
+    print >> f, '\t{ NULL, NULL }\t/* Sentinel */'
+    print >> f, '};'
+    print >> f
+    print >> f, 'static cpyobjheaddef_t cpyobjheaddefs[] = {'
+    for node in database.containerlist:
+        if isinstance(node, PyObjHeadNode):
+            print >> f, '\t{"%s", %s},' % (node.exported_name, node.ptrname)
+    print >> f, '\t{ NULL, NULL }\t/* Sentinel */'
     print >> f, '};'
     print >> f
     print >> f, '/***********************************************************/'

Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py	(original)
+++ pypy/dist/pypy/translator/c/node.py	Fri Jun  9 11:42:39 2006
@@ -1,9 +1,9 @@
 from __future__ import generators
 from pypy.rpython.lltypesystem.lltype import \
      Struct, Array, FixedSizeArray, FuncType, PyObjectType, typeOf, \
-     GcStruct, GcArray, ContainerType, \
+     GcStruct, GcArray, PyStruct, ContainerType, \
      parentlink, Ptr, PyObject, Void, OpaqueType, Float, \
-     RuntimeTypeInfo, getRuntimeTypeInfo, Char, _subarray
+     RuntimeTypeInfo, getRuntimeTypeInfo, Char, _subarray, _pyobjheader
 from pypy.rpython.lltypesystem.llmemory import WeakGcAddress
 from pypy.translator.c.funcgen import FunctionCodeGenerator
 from pypy.translator.c.external import CExternalFunctionCodeGenerator
@@ -16,7 +16,7 @@
 def needs_gcheader(T):
     if not isinstance(T, ContainerType):
         return False
-    if T._gckind == 'raw':
+    if T._gckind != 'gc':
         return False
     if isinstance(T, GcStruct):
         if T._first_struct() != (None, None):
@@ -60,6 +60,9 @@
 
     def setup(self):
         # this computes self.fields
+        if self.STRUCT._hints.get('external'):      # XXX hack
+            self.fields = None    # external definition only
+            return
         self.fields = []
         db = self.db
         STRUCT = self.STRUCT
@@ -101,22 +104,41 @@
         return self.prefix + name
 
     def verbatim_field_name(self, name):
-        assert name.startswith('c_')   # produced in this way by rctypes
-        return name[2:]
+        if name.startswith('c_'):   # produced in this way by rctypes
+            return name[2:]
+        else:
+            # field names have to start with 'c_' or be meant for names that
+            # vanish from the C source, like 'head' if 'inline_head' is set
+            raise Exception("field %r should not be accessed in this way" % (
+                name,))
 
     def c_struct_field_type(self, name):
         return self.STRUCT._flds[name]
 
     def access_expr(self, baseexpr, fldname):
+        if self.STRUCT._hints.get('inline_head'):
+            first, FIRST = self.STRUCT._first_struct()
+            if fldname == first:
+                # "invalid" cast according to C99 but that's what CPython
+                # requires and does all the time :-/
+                return '(*(%s) &(%s))' % (cdecl(self.db.gettype(FIRST), '*'),
+                                          baseexpr)
         fldname = self.c_struct_field_name(fldname)
         return '%s.%s' % (baseexpr, fldname)
 
     def ptr_access_expr(self, baseexpr, fldname):
+        if self.STRUCT._hints.get('inline_head'):
+            first, FIRST = self.STRUCT._first_struct()
+            if fldname == first:
+                # "invalid" cast according to C99 but that's what CPython
+                # requires and does all the time :-/
+                return '(*(%s) %s)' % (cdecl(self.db.gettype(FIRST), '*'),
+                                       baseexpr)
         fldname = self.c_struct_field_name(fldname)
         return '%s->%s' % (baseexpr, fldname)
 
     def definition(self):
-        if self.STRUCT._hints.get('external'):      # XXX hack
+        if self.fields is None:   # external definition only
             return
         yield 'struct %s {' % self.name
         is_empty = True
@@ -421,10 +443,13 @@
             data.append((name, getattr(self.obj, name)))
         
         for name, value in data:
-            c_name = defnode.c_struct_field_name(name)
-            lines = generic_initializationexpr(self.db, value,
-                                               '%s.%s' % (self.name, c_name),
-                                               decoration + name)
+            if isinstance(value, _pyobjheader):   # hack
+                node = self.db.getcontainernode(value)
+                lines = [node.pyobj_initexpr()]
+            else:
+                c_expr = defnode.access_expr(self.name, name)
+                lines = generic_initializationexpr(self.db, value, c_expr,
+                                                   decoration + name)
             for line in lines:
                 yield '\t' + line
             if not lines[0].startswith('/*'):
@@ -711,6 +736,7 @@
         self.obj = obj
         self.name = db.pyobjmaker.computenameof(obj.value)
         self.ptrname = self.name
+        self.exported_name = self.name
         # a list of expressions giving places where this constant PyObject
         # must be copied.  Normally just in the global variable of the same
         # name, but see also StructNode.initializationexpr()  :-(
@@ -725,13 +751,44 @@
         return []
 
 
+class PyObjHeadNode(ContainerNode):
+    nodekind = 'pyobj'
+
+    def __init__(self, db, T, obj):
+        ContainerNode.__init__(self, db, T, obj)
+        self.where_to_copy_me = []
+        self.exported_name = db.namespace.uniquename('cpyobj')
+
+    def basename(self):
+        raise Exception("PyObjHead should always have a parent")
+
+    def enum_dependencies(self):
+        yield self.obj.ob_type
+
+    def pyobj_initexpr(self):
+        parent, parentindex = parentlink(self.obj)
+        assert typeOf(parent)._hints.get('inline_head')
+        typenode = self.db.getcontainernode(self.obj.ob_type._obj)
+        typenode.where_to_copy_me.append('(PyObject **) & %s.ob_type' % (
+            self.name,))
+        return 'PyObject_HEAD_INIT(NULL)'
+
+
+def objectnode_factory(db, T, obj):
+    if isinstance(obj, _pyobjheader):
+        return PyObjHeadNode(db, T, obj)
+    else:
+        return PyObjectNode(db, T, obj)
+
+
 ContainerNodeFactory = {
     Struct:       StructNode,
     GcStruct:     StructNode,
+    PyStruct:     StructNode,
     Array:        ArrayNode,
     GcArray:      ArrayNode,
     FixedSizeArray: FixedSizeArrayNode,
     FuncType:     FuncNode,
     OpaqueType:   opaquenode_factory,
-    PyObjectType: PyObjectNode,
+    PyObjectType: objectnode_factory,
     }

Modified: pypy/dist/pypy/translator/c/primitive.py
==============================================================================
--- pypy/dist/pypy/translator/c/primitive.py	(original)
+++ pypy/dist/pypy/translator/c/primitive.py	Fri Jun  9 11:42:39 2006
@@ -1,5 +1,6 @@
 import sys
 from pypy.rpython.objectmodel import Symbolic, ComputedIntSymbolic
+from pypy.rpython.objectmodel import CDefinedIntSymbolic
 from pypy.rpython.lltypesystem.lltype import *
 from pypy.rpython.lltypesystem.llmemory import Address, fakeaddress, \
      AddressOffset, ItemOffset, ArrayItemsOffset, FieldOffset, \
@@ -14,7 +15,6 @@
 
 def name_signed(value, db):
     if isinstance(value, Symbolic):
-        from pypy.translator.c.gc import REFCOUNT_IMMORTAL
         if isinstance(value, FieldOffset):
             structnode = db.gettypedefnode(value.TYPE)
             return 'offsetof(%s, %s)'%(
@@ -39,8 +39,8 @@
             return '0'
         elif type(value) == GCHeaderOffset:
             return '0'
-        elif type(value) == REFCOUNT_IMMORTAL:
-            return 'REFCOUNT_IMMORTAL'
+        elif isinstance(value, CDefinedIntSymbolic):
+            return str(value.expr)
         elif isinstance(value, ComputedIntSymbolic):
             value = value.compute_fn()
         else:

Modified: pypy/dist/pypy/translator/c/src/module.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/module.h	(original)
+++ pypy/dist/pypy/translator/c/src/module.h	Fri Jun  9 11:42:39 2006
@@ -40,7 +40,7 @@
 		return;	\
 	if (setup_initcode(frozen_initcode, FROZEN_INITCODE_SIZE) < 0) \
 		return;	\
-	if (setup_globalobjects(globalobjectdefs) < 0) \
+	if (setup_globalobjects(globalobjectdefs, cpyobjheaddefs) < 0) \
 		return;
 
 /*** table of global objects ***/
@@ -53,6 +53,11 @@
 } globalobjectdef_t;
 
 typedef struct {
+	char* name;
+	PyObject* cpyobj;
+} cpyobjheaddef_t;
+
+typedef struct {
 	PyObject** p;
 	char* gfunc_name;
 	PyMethodDef ml;
@@ -69,11 +74,29 @@
 
 #ifndef PYPY_NOT_MAIN_FILE
 
-static int setup_globalobjects(globalobjectdef_t* def)
+static int setup_globalobjects(globalobjectdef_t* globtable,
+			       cpyobjheaddef_t* cpyheadtable)
 {
 	PyObject* obj;
-	
-	for (; def->p != NULL; def++) {
+	globalobjectdef_t* def;
+	cpyobjheaddef_t* cpydef;
+
+	/* Store the object given by their heads into the module's dict.
+	   Warning: these object heads might still be invalid, e.g.
+	   typically their ob_type needs patching!
+	   But PyDict_SetItemString() doesn't inspect them...
+	*/
+	for (cpydef = cpyheadtable; cpydef->name != NULL; cpydef++) {
+		obj = cpydef->cpyobj;
+		if (PyDict_SetItemString(this_module_globals,
+					 cpydef->name, obj) < 0)
+			return -1;
+	}
+	/* Patch all locations that need to contain a specific PyObject*.
+	   This must go after the previous loop, otherwise
+	   PyDict_GetItemString() might not find some of them.
+	 */
+	for (def = globtable; def->p != NULL; def++) {
 		obj = PyDict_GetItemString(this_module_globals, def->name);
 		if (obj == NULL) {
 			PyErr_Format(PyExc_AttributeError,
@@ -84,6 +107,16 @@
 		Py_INCREF(obj);
 		*def->p = obj;   /* store the object ref in the global var */
 	}
+	/* All objects should be valid at this point.  Loop again and
+	   make sure all types are ready.
+	*/
+	for (cpydef = cpyheadtable; cpydef->name != NULL; cpydef++) {
+		obj = cpydef->cpyobj;
+		if (PyType_Check(obj)) {
+			if (PyType_Ready((PyTypeObject*) obj) < 0)
+				return -1;
+		}
+	}
 	return 0;
 }
 



More information about the Pypy-commit mailing list