PageRenderTime 60ms CodeModel.GetById 9ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

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