PageRenderTime 74ms CodeModel.GetById 18ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

https://github.com/nicolaslara/pypy
Python | 708 lines | 557 code | 89 blank | 62 comment | 91 complexity | b146482a68946dc7e0d0fa35a71ef3ad MD5 | raw file
  1import os
  2import sys
  3
  4from pypy.rpython.lltypesystem import rffi, lltype
  5from pypy.rpython.annlowlevel import llhelper
  6from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
  7from pypy.objspace.std.typeobject import W_TypeObject
  8from pypy.interpreter.typedef import GetSetProperty
  9from pypy.module.cpyext.api import (
 10    cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
 11    generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
 12    Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
 13    Py_TPFLAGS_HAVE_GETCHARBUFFER,
 14    build_type_checkers, PyObjectFields)
 15from pypy.module.cpyext.pyobject import (
 16    PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
 17    track_reference, RefcountState, borrow_from)
 18from pypy.interpreter.module import Module
 19from pypy.module.cpyext import structmemberdefs
 20from pypy.module.cpyext.modsupport import convert_method_defs
 21from pypy.module.cpyext.state import State
 22from pypy.module.cpyext.methodobject import (
 23    PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef)
 24from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef, _Py_Dealloc
 25from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
 26from pypy.module.cpyext.typeobjectdefs import (
 27    PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
 28    PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
 29from pypy.module.cpyext.slotdefs import (
 30    slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
 31from pypy.interpreter.error import OperationError
 32from pypy.rlib.rstring import rsplit
 33from pypy.rlib.objectmodel import specialize
 34from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
 35from pypy.module.__builtin__.interp_classobj import W_ClassObject
 36from pypy.rlib import jit
 37
 38WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False
 39
 40PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")
 41
 42PyHeapTypeObjectStruct = lltype.ForwardReference()
 43PyHeapTypeObject = lltype.Ptr(PyHeapTypeObjectStruct)
 44PyHeapTypeObjectFields = (
 45    ("ht_type", PyTypeObject),
 46    ("ht_name", PyObject),
 47    ("as_number", PyNumberMethods),
 48    ("as_mapping", PyMappingMethods),
 49    ("as_sequence", PySequenceMethods),
 50    ("as_buffer", PyBufferProcs),
 51    )
 52cpython_struct("PyHeapTypeObject", PyHeapTypeObjectFields, PyHeapTypeObjectStruct,
 53               level=2)
 54
 55class W_GetSetPropertyEx(GetSetProperty):
 56    def __init__(self, getset, w_type):
 57        self.getset = getset
 58        self.name = rffi.charp2str(getset.c_name)
 59        self.w_type = w_type
 60        doc = set = get = None
 61        if doc:
 62            doc = rffi.charp2str(getset.c_doc)
 63        if getset.c_get:
 64            get = GettersAndSetters.getter.im_func
 65        if getset.c_set:
 66            set = GettersAndSetters.setter.im_func
 67        GetSetProperty.__init__(self, get, set, None, doc,
 68                                cls=None, use_closure=True,
 69                                tag="cpyext_1")
 70
 71def PyDescr_NewGetSet(space, getset, w_type):
 72    return space.wrap(W_GetSetPropertyEx(getset, w_type))
 73
 74class W_MemberDescr(GetSetProperty):
 75    def __init__(self, member, w_type):
 76        self.member = member
 77        self.name = rffi.charp2str(member.c_name)
 78        self.w_type = w_type
 79        flags = rffi.cast(lltype.Signed, member.c_flags)
 80        doc = set = None
 81        if member.c_doc:
 82            doc = rffi.charp2str(member.c_doc)
 83        get = GettersAndSetters.member_getter.im_func
 84        del_ = GettersAndSetters.member_delete.im_func
 85        if not (flags & structmemberdefs.READONLY):
 86            set = GettersAndSetters.member_setter.im_func
 87        GetSetProperty.__init__(self, get, set, del_, doc,
 88                                cls=None, use_closure=True,
 89                                tag="cpyext_2")
 90
 91def convert_getset_defs(space, dict_w, getsets, w_type):
 92    getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
 93    if getsets:
 94        i = -1
 95        while True:
 96            i = i + 1
 97            getset = getsets[i]
 98            name = getset.c_name
 99            if not name:
100                break
101            name = rffi.charp2str(name)
102            w_descr = PyDescr_NewGetSet(space, getset, w_type)
103            dict_w[name] = w_descr
104
105def convert_member_defs(space, dict_w, members, w_type):
106    members = rffi.cast(rffi.CArrayPtr(PyMemberDef), members)
107    if members:
108        i = 0
109        while True:
110            member = members[i]
111            name = member.c_name
112            if not name:
113                break
114            name = rffi.charp2str(name)
115            w_descr = space.wrap(W_MemberDescr(member, w_type))
116            dict_w[name] = w_descr
117            i += 1
118
119def update_all_slots(space, w_type, pto):
120    #  XXX fill slots in pto
121
122    typedef = w_type.instancetypedef
123    for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
124        w_descr = w_type.lookup(method_name)
125        if w_descr is None:
126            # XXX special case iternext
127            continue
128
129        slot_func_helper = None
130
131        if slot_func is None and typedef is not None:
132            get_slot = get_slot_tp_function(space, typedef, slot_name)
133            if get_slot:
134                slot_func_helper = get_slot()
135        elif slot_func:
136            slot_func_helper = llhelper(slot_func.api_func.functype,
137                                        slot_func.api_func.get_wrapper(space))
138
139        if slot_func_helper is None:
140            if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
141                os.write(2, method_name + " defined by the type but no slot function defined!\n")
142            continue
143
144        # XXX special case wrapper-functions and use a "specific" slot func
145
146        if len(slot_names) == 1:
147            setattr(pto, slot_names[0], slot_func_helper)
148        else:
149            assert len(slot_names) == 2
150            struct = getattr(pto, slot_names[0])
151            if not struct:
152                assert not space.config.translating
153                assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
154                if slot_names[0] == 'c_tp_as_number':
155                    STRUCT_TYPE = PyNumberMethods
156                elif slot_names[0] == 'c_tp_as_sequence':
157                    STRUCT_TYPE = PySequenceMethods
158                else:
159                    raise AssertionError(
160                        "Structure not allocated: %s" % (slot_names[0],))
161                struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
162                setattr(pto, slot_names[0], struct)
163
164            setattr(struct, slot_names[1], slot_func_helper)
165
166def add_operators(space, dict_w, pto):
167    # XXX support PyObject_HashNotImplemented
168    for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
169        if method_name in dict_w:
170            continue
171        if len(slot_names) == 1:
172            func = getattr(pto, slot_names[0])
173        else:
174            assert len(slot_names) == 2
175            struct = getattr(pto, slot_names[0])
176            if not struct:
177                continue
178            func = getattr(struct, slot_names[1])
179        func_voidp = rffi.cast(rffi.VOIDP, func)
180        if not func:
181            continue
182        if wrapper_func is None and wrapper_func_kwds is None:
183            continue
184        dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
185                wrapper_func_kwds, doc, func_voidp)
186    if pto.c_tp_new:
187        add_tp_new_wrapper(space, dict_w, pto)
188
189@cpython_api([PyObject, PyObject, PyObject], PyObject, external=False)
190def tp_new_wrapper(space, self, w_args, w_kwds):
191    tp_new = rffi.cast(PyTypeObjectPtr, self).c_tp_new
192
193    # Check that the user doesn't do something silly and unsafe like
194    # object.__new__(dict).  To do this, we check that the most
195    # derived base that's not a heap type is this type.
196    # XXX do it
197
198    args_w = space.fixedview(w_args)
199    w_subtype = args_w[0]
200    w_args = space.newtuple(args_w[1:])
201
202    subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
203    try:
204        w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
205    finally:
206        Py_DecRef(space, w_subtype)
207    return w_obj
208
209@specialize.memo()
210def get_new_method_def(space):
211    state = space.fromcache(State)
212    if state.new_method_def:
213        return state.new_method_def
214    from pypy.module.cpyext.modsupport import PyMethodDef
215    ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
216                        immortal=True)
217    ptr.c_ml_name = rffi.str2charp("__new__")
218    lltype.render_immortal(ptr.c_ml_name)
219    rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
220    ptr.c_ml_doc = rffi.str2charp(
221        "T.__new__(S, ...) -> a new object with type S, a subtype of T")
222    lltype.render_immortal(ptr.c_ml_doc)
223    state.new_method_def = ptr
224    return ptr
225
226def setup_new_method_def(space):
227    ptr = get_new_method_def(space)
228    ptr.c_ml_meth = rffi.cast(PyCFunction_typedef,
229        llhelper(tp_new_wrapper.api_func.functype,
230                 tp_new_wrapper.api_func.get_wrapper(space)))
231
232def add_tp_new_wrapper(space, dict_w, pto):
233    if "__new__" in dict_w:
234        return
235    pyo = rffi.cast(PyObject, pto)
236    dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
237                                          from_ref(space, pyo), None)
238
239def inherit_special(space, pto, base_pto):
240    # XXX missing: copy basicsize and flags in a magical way
241    flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
242    base_object_pyo = make_ref(space, space.w_object)
243    base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
244    if base_pto != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
245        if not pto.c_tp_new:
246            pto.c_tp_new = base_pto.c_tp_new
247    Py_DecRef(space, base_object_pyo)
248
249def check_descr(space, w_self, w_type):
250    if not space.is_true(space.isinstance(w_self, w_type)):
251        raise DescrMismatch()
252
253class GettersAndSetters:
254    def getter(self, space, w_self):
255        assert isinstance(self, W_GetSetPropertyEx)
256        check_descr(space, w_self, self.w_type)
257        return generic_cpy_call(
258            space, self.getset.c_get, w_self,
259            self.getset.c_closure)
260
261    def setter(self, space, w_self, w_value):
262        assert isinstance(self, W_GetSetPropertyEx)
263        check_descr(space, w_self, self.w_type)
264        res = generic_cpy_call(
265            space, self.getset.c_set, w_self, w_value,
266            self.getset.c_closure)
267        if rffi.cast(lltype.Signed, res) < 0:
268            state = space.fromcache(State)
269            state.check_and_raise_exception()
270
271    def member_getter(self, space, w_self):
272        assert isinstance(self, W_MemberDescr)
273        check_descr(space, w_self, self.w_type)
274        return PyMember_GetOne(space, w_self, self.member)
275
276    def member_delete(self, space, w_self):
277        assert isinstance(self, W_MemberDescr)
278        check_descr(space, w_self, self.w_type)
279        PyMember_SetOne(space, w_self, self.member, None)
280
281    def member_setter(self, space, w_self, w_value):
282        assert isinstance(self, W_MemberDescr)
283        check_descr(space, w_self, self.w_type)
284        PyMember_SetOne(space, w_self, self.member, w_value)
285
286class W_PyCTypeObject(W_TypeObject):
287    @jit.dont_look_inside
288    def __init__(self, space, pto):
289        bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
290        dict_w = {}
291
292        add_operators(space, dict_w, pto)
293        convert_method_defs(space, dict_w, pto.c_tp_methods, self)
294        convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
295        convert_member_defs(space, dict_w, pto.c_tp_members, self)
296
297        full_name = rffi.charp2str(pto.c_tp_name)
298        if '.' in full_name:
299            module_name, extension_name = rsplit(full_name, ".", 1)
300            dict_w["__module__"] = space.wrap(module_name)
301        else:
302            extension_name = full_name
303
304        W_TypeObject.__init__(self, space, extension_name,
305            bases_w or [space.w_object], dict_w)
306        if not space.is_true(space.issubtype(self, space.w_type)):
307            self.flag_cpytype = True
308        self.flag_heaptype = False
309
310@bootstrap_function
311def init_typeobject(space):
312    # Probably a hack
313    space.model.typeorder[W_PyCTypeObject] = [(W_PyCTypeObject, None),
314                                              (W_TypeObject, None),
315                                              (W_Root, None)]
316
317    make_typedescr(space.w_type.instancetypedef,
318                   basestruct=PyTypeObject,
319                   alloc=type_alloc,
320                   attach=type_attach,
321                   realize=type_realize,
322                   dealloc=type_dealloc)
323
324    # some types are difficult to create because of cycles.
325    # - object.ob_type = type
326    # - type.ob_type   = type
327    # - tuple.ob_type  = type
328    # - type.tp_base   = object
329    # - tuple.tp_base  = object
330    # - type.tp_bases is a tuple
331    # - object.tp_bases is a tuple
332    # - tuple.tp_bases is a tuple
333
334    # insert null placeholders to please create_ref()
335    track_reference(space, lltype.nullptr(PyObject.TO), space.w_type)
336    track_reference(space, lltype.nullptr(PyObject.TO), space.w_object)
337    track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple)
338    track_reference(space, lltype.nullptr(PyObject.TO), space.w_str)
339
340    # create the objects
341    py_type = create_ref(space, space.w_type)
342    py_object = create_ref(space, space.w_object)
343    py_tuple = create_ref(space, space.w_tuple)
344    py_str = create_ref(space, space.w_str)
345
346    # form cycles
347    pto_type = rffi.cast(PyTypeObjectPtr, py_type)
348    py_type.c_ob_type = pto_type
349    py_object.c_ob_type = pto_type
350    py_tuple.c_ob_type = pto_type
351
352    pto_object = rffi.cast(PyTypeObjectPtr, py_object)
353    pto_type.c_tp_base = pto_object
354    pto_tuple = rffi.cast(PyTypeObjectPtr, py_tuple)
355    pto_tuple.c_tp_base = pto_object
356
357    pto_type.c_tp_bases.c_ob_type = pto_tuple
358    pto_object.c_tp_bases.c_ob_type = pto_tuple
359    pto_tuple.c_tp_bases.c_ob_type = pto_tuple
360
361    for typ in (py_type, py_object, py_tuple, py_str):
362        heaptype = rffi.cast(PyHeapTypeObject, typ)
363        heaptype.c_ht_name.c_ob_type = pto_type
364
365    # Restore the mapping
366    track_reference(space, py_type, space.w_type, replace=True)
367    track_reference(space, py_object, space.w_object, replace=True)
368    track_reference(space, py_tuple, space.w_tuple, replace=True)
369    track_reference(space, py_str, space.w_str, replace=True)
370
371
372@cpython_api([PyObject], lltype.Void, external=False)
373def subtype_dealloc(space, obj):
374    pto = obj.c_ob_type
375    base = pto
376    this_func_ptr = llhelper(subtype_dealloc.api_func.functype,
377            subtype_dealloc.api_func.get_wrapper(space))
378    while base.c_tp_dealloc == this_func_ptr:
379        base = base.c_tp_base
380        assert base
381    dealloc = base.c_tp_dealloc
382    # XXX call tp_del if necessary
383    generic_cpy_call(space, dealloc, obj)
384    # XXX cpy decrefs the pto here but we do it in the base-dealloc
385    # hopefully this does not clash with the memory model assumed in
386    # extension modules
387
388@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
389             error=CANNOT_FAIL)
390def str_segcount(space, w_obj, ref):
391    if ref:
392        ref[0] = space.len_w(w_obj)
393    return 1
394
395@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
396             external=False, error=-1)
397def str_getreadbuffer(space, w_str, segment, ref):
398    from pypy.module.cpyext.stringobject import PyString_AsString
399    if segment != 0:
400        raise OperationError(space.w_SystemError, space.wrap
401                             ("accessing non-existent string segment"))
402    pyref = make_ref(space, w_str)
403    ref[0] = PyString_AsString(space, pyref)
404    # Stolen reference: the object has better exist somewhere else
405    Py_DecRef(space, pyref)
406    return space.len_w(w_str)
407
408@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
409             external=False, error=-1)
410def str_getcharbuffer(space, w_str, segment, ref):
411    from pypy.module.cpyext.stringobject import PyString_AsString
412    if segment != 0:
413        raise OperationError(space.w_SystemError, space.wrap
414                             ("accessing non-existent string segment"))
415    pyref = make_ref(space, w_str)
416    ref[0] = PyString_AsString(space, pyref)
417    # Stolen reference: the object has better exist somewhere else
418    Py_DecRef(space, pyref)
419    return space.len_w(w_str)
420
421def setup_string_buffer_procs(space, pto):
422    c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
423    c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
424                                      str_segcount.api_func.get_wrapper(space))
425    c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype,
426                                 str_getreadbuffer.api_func.get_wrapper(space))
427    c_buf.c_bf_getcharbuffer = llhelper(str_getcharbuffer.api_func.functype,
428                                 str_getcharbuffer.api_func.get_wrapper(space))
429    pto.c_tp_as_buffer = c_buf
430    pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
431
432@cpython_api([PyObject], lltype.Void, external=False)
433def type_dealloc(space, obj):
434    from pypy.module.cpyext.object import PyObject_dealloc
435    obj_pto = rffi.cast(PyTypeObjectPtr, obj)
436    base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
437    Py_DecRef(space, obj_pto.c_tp_bases)
438    Py_DecRef(space, obj_pto.c_tp_mro)
439    Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
440    Py_DecRef(space, obj_pto.c_tp_dict)
441    if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
442        heaptype = rffi.cast(PyHeapTypeObject, obj)
443        Py_DecRef(space, heaptype.c_ht_name)
444        Py_DecRef(space, base_pyo)
445        PyObject_dealloc(space, obj)
446
447
448def type_alloc(space, w_metatype):
449    size = rffi.sizeof(PyHeapTypeObject)
450    metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
451    # Don't increase refcount for non-heaptypes
452    if metatype:
453        flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
454        if not flags & Py_TPFLAGS_HEAPTYPE:
455            Py_DecRef(space, w_metatype)
456
457    heaptype = lltype.malloc(PyHeapTypeObject.TO,
458                             flavor='raw', zero=True)
459    pto = heaptype.c_ht_type
460    pto.c_ob_refcnt = 1
461    pto.c_ob_type = metatype
462    pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
463    pto.c_tp_as_number = heaptype.c_as_number
464    pto.c_tp_as_sequence = heaptype.c_as_sequence
465    pto.c_tp_as_mapping = heaptype.c_as_mapping
466    pto.c_tp_as_buffer = heaptype.c_as_buffer
467    
468    return rffi.cast(PyObject, heaptype)
469
470def type_attach(space, py_obj, w_type):
471    """
472    Fills a newly allocated PyTypeObject from an existing type.
473    """
474    from pypy.module.cpyext.object import PyObject_Del
475
476    assert isinstance(w_type, W_TypeObject)
477
478    pto = rffi.cast(PyTypeObjectPtr, py_obj)
479
480    typedescr = get_typedescr(w_type.instancetypedef)
481
482    # dealloc
483    pto.c_tp_dealloc = typedescr.get_dealloc(space)
484    # buffer protocol
485    if space.is_w(w_type, space.w_str):
486        setup_string_buffer_procs(space, pto)
487
488    pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
489            PyObject_Del.api_func.get_wrapper(space))
490    pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
491            PyType_GenericAlloc.api_func.get_wrapper(space))
492    if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
493        w_typename = space.getattr(w_type, space.wrap('__name__'))
494        heaptype = rffi.cast(PyHeapTypeObject, pto)
495        heaptype.c_ht_name = make_ref(space, w_typename)
496        from pypy.module.cpyext.stringobject import PyString_AsString
497        pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name)
498    else:
499        pto.c_tp_name = rffi.str2charp(w_type.getname(space))
500    pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
501    pto.c_tp_itemsize = 0
502    # uninitialized fields:
503    # c_tp_print, c_tp_getattr, c_tp_setattr
504    # XXX implement
505    # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html )
506    w_base = best_base(space, w_type.bases_w)
507    pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
508
509    finish_type_1(space, pto)
510    finish_type_2(space, pto, w_type)
511
512    pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
513    if pto.c_tp_base:
514        if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
515            pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
516
517    # will be filled later on with the correct value
518    # may not be 0
519    if space.is_w(w_type, space.w_object):
520        pto.c_tp_new = rffi.cast(newfunc, 1)
521    update_all_slots(space, w_type, pto)
522    pto.c_tp_flags |= Py_TPFLAGS_READY
523    return pto
524
525@cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
526def PyType_Ready(space, pto):
527    if pto.c_tp_flags & Py_TPFLAGS_READY:
528        return 0
529    type_realize(space, rffi.cast(PyObject, pto))
530    return 0
531
532def type_realize(space, py_obj):
533    pto = rffi.cast(PyTypeObjectPtr, py_obj)
534    assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
535    pto.c_tp_flags |= Py_TPFLAGS_READYING
536    try:
537        w_obj = _type_realize(space, py_obj)
538    finally:
539        pto.c_tp_flags &= ~Py_TPFLAGS_READYING
540    pto.c_tp_flags |= Py_TPFLAGS_READY
541    return w_obj
542
543def solid_base(space, w_type):
544    typedef = w_type.instancetypedef
545    return space.gettypeobject(typedef)
546
547def best_base(space, bases_w):
548    if not bases_w:
549        return None
550
551    w_winner = None
552    w_base = None
553    for w_base_i in bases_w:
554        if isinstance(w_base_i, W_ClassObject):
555            # old-style base
556            continue
557        assert isinstance(w_base_i, W_TypeObject)
558        w_candidate = solid_base(space, w_base_i)
559        if not w_winner:
560            w_winner = w_candidate
561            w_base = w_base_i
562        elif space.abstract_issubclass_w(w_winner, w_candidate):
563            pass
564        elif space.abstract_issubclass_w(w_candidate, w_winner):
565            w_winner = w_candidate
566            w_base = w_base_i
567        else:
568            raise OperationError(
569                space.w_TypeError,
570                space.wrap("multiple bases have instance lay-out conflict"))
571    if w_base is None:
572        raise OperationError(
573            space.w_TypeError,
574                space.wrap("a new-style class can't have only classic bases"))
575
576    return w_base
577
578def inherit_slots(space, pto, w_base):
579    # XXX missing: nearly everything
580    base_pyo = make_ref(space, w_base)
581    try:
582        base = rffi.cast(PyTypeObjectPtr, base_pyo)
583        if not pto.c_tp_dealloc:
584            pto.c_tp_dealloc = base.c_tp_dealloc
585        if not pto.c_tp_init:
586            pto.c_tp_init = base.c_tp_init
587        if not pto.c_tp_alloc:
588            pto.c_tp_alloc = base.c_tp_alloc
589        # XXX check for correct GC flags!
590        if not pto.c_tp_free:
591            pto.c_tp_free = base.c_tp_free
592        if not pto.c_tp_setattro:
593            pto.c_tp_setattro = base.c_tp_setattro
594    finally:
595        Py_DecRef(space, base_pyo)
596
597def _type_realize(space, py_obj):
598    """
599    Creates an interpreter type from a PyTypeObject structure.
600    """
601    # missing:
602    # setting __doc__ if not defined and tp_doc defined
603    # inheriting tp_as_* slots
604    # unsupported:
605    # tp_mro, tp_subclasses
606    py_type = rffi.cast(PyTypeObjectPtr, py_obj)
607
608    if not py_type.c_tp_base:
609        # borrowed reference, but w_object is unlikely to disappear
610        base = make_ref(space, space.w_object)
611        Py_DecRef(space, base)
612        py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
613
614    finish_type_1(space, py_type)
615
616    w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
617
618    w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
619    track_reference(space, py_obj, w_obj)
620    w_obj.__init__(space, py_type)
621    w_obj.ready()
622
623    finish_type_2(space, py_type, w_obj)
624
625    state = space.fromcache(RefcountState)
626    state.non_heaptypes_w.append(w_obj)
627
628    return w_obj
629
630def finish_type_1(space, pto):
631    """
632    Sets up tp_bases, necessary before creating the interpreter type.
633    """
634    base = pto.c_tp_base
635    base_pyo = rffi.cast(PyObject, pto.c_tp_base)
636    if base and not base.c_tp_flags & Py_TPFLAGS_READY:
637        type_realize(space, rffi.cast(PyObject, base_pyo))
638    if base and not pto.c_ob_type: # will be filled later
639        pto.c_ob_type = base.c_ob_type
640    if not pto.c_tp_bases:
641        if not base:
642            bases = space.newtuple([])
643        else:
644            bases = space.newtuple([from_ref(space, base_pyo)])
645        pto.c_tp_bases = make_ref(space, bases)
646
647def finish_type_2(space, pto, w_obj):
648    """
649    Sets up other attributes, when the interpreter type has been created.
650    """
651    pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
652    base = pto.c_tp_base
653    if base:
654        inherit_special(space, pto, base)
655    for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
656        inherit_slots(space, pto, w_base)
657
658    if not pto.c_tp_setattro:
659        from pypy.module.cpyext.object import PyObject_GenericSetAttr
660        pto.c_tp_setattro = llhelper(
661            PyObject_GenericSetAttr.api_func.functype,
662            PyObject_GenericSetAttr.api_func.get_wrapper(space))
663
664    if w_obj.is_cpytype():
665        Py_DecRef(space, pto.c_tp_dict)
666        w_dict = w_obj.getdict(space)
667        pto.c_tp_dict = make_ref(space, w_dict)
668
669@cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
670def PyType_IsSubtype(space, a, b):
671    """Return true if a is a subtype of b.
672    """
673    w_type1 = from_ref(space, rffi.cast(PyObject, a))
674    w_type2 = from_ref(space, rffi.cast(PyObject, b))
675    return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?
676
677@cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject)
678def PyType_GenericAlloc(space, type, nitems):
679    from pypy.module.cpyext.object import _PyObject_NewVar
680    return _PyObject_NewVar(space, type, nitems)
681
682@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
683def PyType_GenericNew(space, type, w_args, w_kwds):
684    return generic_cpy_call(
685        space, type.c_tp_alloc, type, 0)
686
687@cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL)
688def _PyType_Lookup(space, type, w_name):
689    """Internal API to look for a name through the MRO.
690    This returns a borrowed reference, and doesn't set an exception!"""
691    w_type = from_ref(space, rffi.cast(PyObject, type))
692    assert isinstance(w_type, W_TypeObject)
693
694    if not space.isinstance_w(w_name, space.w_str):
695        return None
696    name = space.str_w(w_name)
697    w_obj = w_type.lookup(name)
698    return borrow_from(w_type, w_obj)
699
700@cpython_api([PyTypeObjectPtr], lltype.Void)
701def PyType_Modified(space, w_obj):
702    """Invalidate the internal lookup cache for the type and all of its
703    subtypes.  This function must be called after any manual
704    modification of the attributes or base classes of the type.
705    """
706    # PyPy already takes care of direct modifications to type.__dict__
707    # (which is a W_DictProxyObject).
708    pass