typeobject.py 38.4 KB
Newer Older
1
2
import os

Manuel Jacob's avatar
Manuel Jacob committed
3
4
5
from rpython.rlib import jit
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rstring import rsplit
Alexander Hesse's avatar
Alexander Hesse committed
6
from rpython.rtyper.annlowlevel import llhelper
Manuel Jacob's avatar
Manuel Jacob committed
7
8
from rpython.rtyper.lltypesystem import rffi, lltype

9
from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
Philip Jenvey's avatar
Philip Jenvey committed
10
from pypy.interpreter.error import oefmt
11
12
from pypy.interpreter.typedef import (GetSetProperty, TypeDef,
        interp_attrproperty, interp_attrproperty, interp2app)
Manuel Jacob's avatar
Manuel Jacob committed
13
14
from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
from pypy.module.cpyext import structmemberdefs
15
from pypy.module.cpyext.api import (
Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
16
    cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
17
    generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
18
    Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
Matti Picus's avatar
Matti Picus committed
19
    Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder,
20
    PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr,
21
22
    Py_TPFLAGS_HAVE_NEWBUFFER, Py_TPFLAGS_CHECKTYPES,
    Py_TPFLAGS_HAVE_INPLACEOPS)
23
from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
24
    W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
25
    W_PyCMethodObject, W_PyCFunctionObject)
Manuel Jacob's avatar
Manuel Jacob committed
26
from pypy.module.cpyext.modsupport import convert_method_defs
27
28
from pypy.module.cpyext.pyobject import (
    PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
29
    track_reference, Py_DecRef, as_pyobj)
Manuel Jacob's avatar
Manuel Jacob committed
30
31
from pypy.module.cpyext.slotdefs import (
    slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
32
33
from pypy.module.cpyext.state import State
from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
34
from pypy.module.cpyext.typeobjectdefs import (
35
    PyGetSetDef, PyMemberDef, newfunc,
36
    PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
Manuel Jacob's avatar
Manuel Jacob committed
37
38
from pypy.objspace.std.typeobject import W_TypeObject, find_best_base

39
40
41
42
43

WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False

PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")

44
45
46
47
48
49
50
51
52
53
54
55
56
PyHeapTypeObjectStruct = lltype.ForwardReference()
PyHeapTypeObject = lltype.Ptr(PyHeapTypeObjectStruct)
PyHeapTypeObjectFields = (
    ("ht_type", PyTypeObject),
    ("ht_name", PyObject),
    ("as_number", PyNumberMethods),
    ("as_mapping", PyMappingMethods),
    ("as_sequence", PySequenceMethods),
    ("as_buffer", PyBufferProcs),
    )
cpython_struct("PyHeapTypeObject", PyHeapTypeObjectFields, PyHeapTypeObjectStruct,
               level=2)

57
class W_GetSetPropertyEx(GetSetProperty):
58
    def __init__(self, getset, w_type):
59
60
        self.getset = getset
        self.name = rffi.charp2str(getset.c_name)
61
        self.w_type = w_type
62
63
64
65
66
67
68
69
70
71
72
        doc = set = get = None
        if doc:
            doc = rffi.charp2str(getset.c_doc)
        if getset.c_get:
            get = GettersAndSetters.getter.im_func
        if getset.c_set:
            set = GettersAndSetters.setter.im_func
        GetSetProperty.__init__(self, get, set, None, doc,
                                cls=None, use_closure=True,
                                tag="cpyext_1")

73
74
def PyDescr_NewGetSet(space, getset, w_type):
    return space.wrap(W_GetSetPropertyEx(getset, w_type))
75
76

class W_MemberDescr(GetSetProperty):
77
    name = 'member_descriptor'
78
    def __init__(self, member, w_type):
79
80
        self.member = member
        self.name = rffi.charp2str(member.c_name)
81
        self.w_type = w_type
82
83
84
85
86
87
88
89
90
91
92
93
        flags = rffi.cast(lltype.Signed, member.c_flags)
        doc = set = None
        if member.c_doc:
            doc = rffi.charp2str(member.c_doc)
        get = GettersAndSetters.member_getter.im_func
        del_ = GettersAndSetters.member_delete.im_func
        if not (flags & structmemberdefs.READONLY):
            set = GettersAndSetters.member_setter.im_func
        GetSetProperty.__init__(self, get, set, del_, doc,
                                cls=None, use_closure=True,
                                tag="cpyext_2")

94
95
96
97
98
99
100
101
102
103
104
105
# change the typedef name
W_MemberDescr.typedef = TypeDef(
    "member_descriptor",
    __get__ = interp2app(GetSetProperty.descr_property_get),
    __set__ = interp2app(GetSetProperty.descr_property_set),
    __delete__ = interp2app(GetSetProperty.descr_property_del),
    __name__ = interp_attrproperty('name', cls=GetSetProperty),
    __objclass__ = GetSetProperty(GetSetProperty.descr_get_objclass),
    __doc__ = interp_attrproperty('doc', cls=GetSetProperty),
    )
assert not W_MemberDescr.typedef.acceptable_as_base_class  # no __new__

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
PyDescrObject = lltype.ForwardReference()
PyDescrObjectPtr = lltype.Ptr(PyDescrObject)
PyDescrObjectFields = PyObjectFields + (
    ("d_type", PyTypeObjectPtr),
    ("d_name", PyObject),
    )
cpython_struct("PyDescrObject", PyDescrObjectFields,
               PyDescrObject)

PyMemberDescrObjectStruct = lltype.ForwardReference()
PyMemberDescrObject = lltype.Ptr(PyMemberDescrObjectStruct)
PyMemberDescrObjectFields = PyDescrObjectFields + (
    ("d_member", lltype.Ptr(PyMemberDef)),
    )
cpython_struct("PyMemberDescrObject", PyMemberDescrObjectFields,
               PyMemberDescrObjectStruct, level=2)

123
124
125
126
127
128
129
130
PyGetSetDescrObjectStruct = lltype.ForwardReference()
PyGetSetDescrObject = lltype.Ptr(PyGetSetDescrObjectStruct)
PyGetSetDescrObjectFields = PyDescrObjectFields + (
    ("d_getset", lltype.Ptr(PyGetSetDef)),
    )
cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields,
               PyGetSetDescrObjectStruct, level=2)

131
132
133
134
135
136
137
138
PyMethodDescrObjectStruct = lltype.ForwardReference()
PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct)
PyMethodDescrObjectFields = PyDescrObjectFields + (
    ("d_method", lltype.Ptr(PyMethodDef)),
    )
cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields,
               PyMethodDescrObjectStruct, level=2)

139
140
141
142
143
144
145
@bootstrap_function
def init_memberdescrobject(space):
    make_typedescr(W_MemberDescr.typedef,
                   basestruct=PyMemberDescrObject.TO,
                   attach=memberdescr_attach,
                   realize=memberdescr_realize,
                   )
146
147
148
149
    make_typedescr(W_GetSetPropertyEx.typedef,
                   basestruct=PyGetSetDescrObject.TO,
                   attach=getsetdescr_attach,
                   )
150
151
152
153
154
155
156
157
158
159
    make_typedescr(W_PyCClassMethodObject.typedef,
                   basestruct=PyMethodDescrObject.TO,
                   attach=methoddescr_attach,
                   realize=classmethoddescr_realize,
                   )
    make_typedescr(W_PyCMethodObject.typedef,
                   basestruct=PyMethodDescrObject.TO,
                   attach=methoddescr_attach,
                   realize=methoddescr_realize,
                   )
160
161
162
163
164
165
166
167

def memberdescr_attach(space, py_obj, w_obj):
    """
    Fills a newly allocated PyMemberDescrObject with the given W_MemberDescr
    object. The values must not be modified.
    """
    py_memberdescr = rffi.cast(PyMemberDescrObject, py_obj)
    # XXX assign to d_dname, d_type?
Matti Picus's avatar
Matti Picus committed
168
    assert isinstance(w_obj, W_MemberDescr)
169
170
171
    py_memberdescr.c_d_member = w_obj.member

def memberdescr_realize(space, obj):
Ronan Lamy's avatar
Ronan Lamy committed
172
    # XXX NOT TESTED When is this ever called?
Matti Picus's avatar
Matti Picus committed
173
    member = rffi.cast(lltype.Ptr(PyMemberDef), obj)
174
175
176
177
178
179
    w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
    w_obj = space.allocate_instance(W_MemberDescr, w_type)
    w_obj.__init__(member, w_type)
    track_reference(space, obj, w_obj)
    return w_obj

180
181
182
183
184
185
186
187
188
189
def getsetdescr_attach(space, py_obj, w_obj):
    """
    Fills a newly allocated PyGetSetDescrObject with the given W_GetSetPropertyEx
    object. The values must not be modified.
    """
    py_getsetdescr = rffi.cast(PyGetSetDescrObject, py_obj)
    # XXX assign to d_dname, d_type?
    assert isinstance(w_obj, W_GetSetPropertyEx)
    py_getsetdescr.c_d_getset = w_obj.getset

190
191
192
193
194
195
196
def methoddescr_attach(space, py_obj, w_obj):
    py_methoddescr = rffi.cast(PyMethodDescrObject, py_obj)
    # XXX assign to d_dname, d_type?
    assert isinstance(w_obj, W_PyCFunctionObject)
    py_methoddescr.c_d_method = w_obj.ml

def classmethoddescr_realize(space, obj):
Ronan Lamy's avatar
Ronan Lamy committed
197
    # XXX NOT TESTED When is this ever called?
198
199
200
201
202
203
204
205
    method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
    w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
    w_obj = space.allocate_instance(W_PyCClassMethodObject, w_type)
    w_obj.__init__(space, method, w_type)
    track_reference(space, obj, w_obj)
    return w_obj

def methoddescr_realize(space, obj):
Ronan Lamy's avatar
Ronan Lamy committed
206
    # XXX NOT TESTED When is this ever called?
207
208
209
210
211
212
213
    method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
    w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
    w_obj = space.allocate_instance(W_PyCMethodObject, w_type)
    w_obj.__init__(space, method, w_type)
    track_reference(space, obj, w_obj)
    return w_obj

214
def convert_getset_defs(space, dict_w, getsets, w_type):
215
216
217
218
219
220
221
222
223
224
    getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
    if getsets:
        i = -1
        while True:
            i = i + 1
            getset = getsets[i]
            name = getset.c_name
            if not name:
                break
            name = rffi.charp2str(name)
225
            w_descr = PyDescr_NewGetSet(space, getset, w_type)
226
227
            dict_w[name] = w_descr

228
def convert_member_defs(space, dict_w, members, w_type):
229
230
231
232
233
234
235
236
237
    members = rffi.cast(rffi.CArrayPtr(PyMemberDef), members)
    if members:
        i = 0
        while True:
            member = members[i]
            name = member.c_name
            if not name:
                break
            name = rffi.charp2str(name)
238
            w_descr = space.wrap(W_MemberDescr(member, w_type))
239
240
241
            dict_w[name] = w_descr
            i += 1

242
def update_all_slots(space, w_type, pto):
243
    # fill slots in pto
Armin Rigo's avatar
Armin Rigo committed
244
245
246
247
    # Not very sure about it, but according to
    # test_call_tp_dealloc_when_created_from_python, we should not
    # overwrite slots that are already set: these ones are probably
    # coming from a parent C type.
248

249
    typedef = w_type.layout.typedef
250
251
252
    if w_type is not space.w_object:
        # XXX fix, to prevent problems with slot lookups
        assert typedef is not space.w_object.layout.typedef
253
    for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
254
        w_descr = w_type.lookup(method_name)
255
256
257
        if w_descr is None:
            # XXX special case iternext
            continue
258
259
260
261

        slot_func_helper = None

        if slot_func is None and typedef is not None:
262
            get_slot = get_slot_tp_function(space, typedef, slot_name)
263
264
265
266
267
268
269
            if get_slot:
                slot_func_helper = get_slot()
        elif slot_func:
            slot_func_helper = llhelper(slot_func.api_func.functype,
                                        slot_func.api_func.get_wrapper(space))

        if slot_func_helper is None:
270
            if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
271
272
                os.write(2, "%s defined by %s but no slot function defined!\n" % (
                        method_name, w_type.getname(space)))
273
            continue
274

275
276
        # XXX special case wrapper-functions and use a "specific" slot func

277
        if len(slot_names) == 1:
Armin Rigo's avatar
Armin Rigo committed
278
279
            if not getattr(pto, slot_names[0]):
                setattr(pto, slot_names[0], slot_func_helper)
280
        elif (w_type.getname(space) in ('list', 'tuple') and
281
282
283
284
              slot_names[0] == 'c_tp_as_number'):
            # XXX hack - hwo can we generalize this? The problem is method
            # names like __mul__ map to more than one slot, and we have no
            # convenient way to indicate which slots CPython have filled
285
            #
286
287
288
            # We need at least this special case since Numpy checks that
            # (list, tuple) do __not__ fill tp_as_number
            pass
289
        else:
290
291
            assert len(slot_names) == 2
            struct = getattr(pto, slot_names[0])
292
            if not struct:
Armin Rigo's avatar
Armin Rigo committed
293
                #assert not space.config.translating
294
                assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
295
                if slot_names[0] == 'c_tp_as_number':
296
                    STRUCT_TYPE = PyNumberMethods
297
298
                elif slot_names[0] == 'c_tp_as_sequence':
                    STRUCT_TYPE = PySequenceMethods
299
300
                elif slot_names[0] == 'c_tp_as_buffer':
                    STRUCT_TYPE = PyBufferProcs
301
302
                else:
                    raise AssertionError(
303
                        "Structure not allocated: %s" % (slot_names[0],))
304
                struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
305
                setattr(pto, slot_names[0], struct)
306

Armin Rigo's avatar
Armin Rigo committed
307
308
            if not getattr(struct, slot_names[1]):
                setattr(struct, slot_names[1], slot_func_helper)
309
310
311

def add_operators(space, dict_w, pto):
    # XXX support PyObject_HashNotImplemented
312
    for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
313
314
        if method_name in dict_w:
            continue
315
        offset = [rffi.offsetof(lltype.typeOf(pto).TO, slot_names[0])]
316
317
        if len(slot_names) == 1:
            func = getattr(pto, slot_names[0])
318
        else:
319
320
            assert len(slot_names) == 2
            struct = getattr(pto, slot_names[0])
321
322
            if not struct:
                continue
323
            offset.append(rffi.offsetof(lltype.typeOf(struct).TO, slot_names[1]))
324
            func = getattr(struct, slot_names[1])
Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
325
        func_voidp = rffi.cast(rffi.VOIDP, func)
326
327
328
329
        if not func:
            continue
        if wrapper_func is None and wrapper_func_kwds is None:
            continue
330
331
332
        w_obj = W_PyCWrapperObject(space, pto, method_name, wrapper_func,
                wrapper_func_kwds, doc, func_voidp, offset=offset)
        dict_w[method_name] = space.wrap(w_obj)
333
334
335
    if pto.c_tp_new:
        add_tp_new_wrapper(space, dict_w, pto)

336
@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None)
337
def tp_new_wrapper(space, self, w_args, w_kwds):
338
339
    self_pytype = rffi.cast(PyTypeObjectPtr, self)
    tp_new = self_pytype.c_tp_new
340
341
342
343
344
345
346
347
348

    # Check that the user doesn't do something silly and unsafe like
    # object.__new__(dict).  To do this, we check that the most
    # derived base that's not a heap type is this type.
    # XXX do it

    args_w = space.fixedview(w_args)
    w_subtype = args_w[0]
    w_args = space.newtuple(args_w[1:])
Armin Rigo's avatar
Armin Rigo committed
349
350
    if not space.is_true(w_kwds):
        w_kwds = None
351
352

    try:
353
        subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
354
        w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
355
356
    finally:
        Py_DecRef(space, w_subtype)
357
    return w_obj
358
359
360
361
362
363

@specialize.memo()
def get_new_method_def(space):
    state = space.fromcache(State)
    if state.new_method_def:
        return state.new_method_def
364
365
    ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
                        immortal=True)
366
    ptr.c_ml_name = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp("__new__"))
367
    lltype.render_immortal(ptr.c_ml_name)
368
    rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
369
370
    ptr.c_ml_doc = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp(
        "T.__new__(S, ...) -> a new object with type S, a subtype of T"))
371
    lltype.render_immortal(ptr.c_ml_doc)
372
373
374
375
376
    state.new_method_def = ptr
    return ptr

def setup_new_method_def(space):
    ptr = get_new_method_def(space)
377
    ptr.c_ml_meth = rffi.cast(PyCFunction_typedef,
378
379
        llhelper(tp_new_wrapper.api_func.functype,
                 tp_new_wrapper.api_func.get_wrapper(space)))
380
381
382
383
384
385

def add_tp_new_wrapper(space, dict_w, pto):
    if "__new__" in dict_w:
        return
    pyo = rffi.cast(PyObject, pto)
    dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
386
                                          from_ref(space, pyo), None)
387
388
389

def inherit_special(space, pto, base_pto):
    # XXX missing: copy basicsize and flags in a magical way
390
391
392
    # (minimally, if tp_basicsize is zero we copy it from the base)
    if not pto.c_tp_basicsize:
        pto.c_tp_basicsize = base_pto.c_tp_basicsize
Matti Picus's avatar
Matti Picus committed
393
394
    if pto.c_tp_itemsize < base_pto.c_tp_itemsize:
        pto.c_tp_itemsize = base_pto.c_tp_itemsize
395
396
    pto.c_tp_flags |= base_pto.c_tp_flags & Py_TPFLAGS_CHECKTYPES
    pto.c_tp_flags |= base_pto.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
397

398
def check_descr(space, w_self, w_type):
399
    if not space.isinstance_w(w_self, w_type):
400
401
402
403
        raise DescrMismatch()

class GettersAndSetters:
    def getter(self, space, w_self):
404
        assert isinstance(self, W_GetSetPropertyEx)
405
        check_descr(space, w_self, self.w_type)
406
407
408
409
410
        return generic_cpy_call(
            space, self.getset.c_get, w_self,
            self.getset.c_closure)

    def setter(self, space, w_self, w_value):
411
        assert isinstance(self, W_GetSetPropertyEx)
412
        check_descr(space, w_self, self.w_type)
413
414
415
416
417
418
419
420
        res = generic_cpy_call(
            space, self.getset.c_set, w_self, w_value,
            self.getset.c_closure)
        if rffi.cast(lltype.Signed, res) < 0:
            state = space.fromcache(State)
            state.check_and_raise_exception()

    def member_getter(self, space, w_self):
421
        assert isinstance(self, W_MemberDescr)
422
        check_descr(space, w_self, self.w_type)
423
424
425
426
427
428
        pyref = make_ref(space, w_self)
        try:
            return PyMember_GetOne(
                space, rffi.cast(rffi.CCHARP, pyref), self.member)
        finally:
            Py_DecRef(space, pyref)
429
430

    def member_delete(self, space, w_self):
431
        assert isinstance(self, W_MemberDescr)
432
        check_descr(space, w_self, self.w_type)
433
434
435
436
437
438
        pyref = make_ref(space, w_self)
        try:
            PyMember_SetOne(
                space, rffi.cast(rffi.CCHARP, pyref), self.member, None)
        finally:
            Py_DecRef(space, pyref)
439
440

    def member_setter(self, space, w_self, w_value):
441
        assert isinstance(self, W_MemberDescr)
442
        check_descr(space, w_self, self.w_type)
443
444
445
446
447
448
        pyref = make_ref(space, w_self)
        try:
            PyMember_SetOne(
                space, rffi.cast(rffi.CCHARP, pyref), self.member, w_value)
        finally:
            Py_DecRef(space, pyref)
449
450

class W_PyCTypeObject(W_TypeObject):
451
    @jit.dont_look_inside
452
453
454
455
456
    def __init__(self, space, pto):
        bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
        dict_w = {}

        add_operators(space, dict_w, pto)
457
458
459
        convert_method_defs(space, dict_w, pto.c_tp_methods, self)
        convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
        convert_member_defs(space, dict_w, pto.c_tp_members, self)
460

461
        name = rffi.charp2str(pto.c_tp_name)
Armin Rigo's avatar
Armin Rigo committed
462
463
        new_layout = (pto.c_tp_basicsize > rffi.sizeof(PyObject.TO) or
                      pto.c_tp_itemsize > 0)
464

465
        W_TypeObject.__init__(self, space, name,
Armin Rigo's avatar
Armin Rigo committed
466
            bases_w or [space.w_object], dict_w, force_new_layout=new_layout)
467
        self.flag_cpytype = True
Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
468
        self.flag_heaptype = False
469
470
471
472
473
474
        # if a sequence or a mapping, then set the flag to force it
        if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
            self.flag_map_or_seq = 'S'
        elif (pto.c_tp_as_mapping and pto.c_tp_as_mapping.c_mp_subscript and
              not (pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_slice)):
            self.flag_map_or_seq = 'M'
Armin Rigo's avatar
Armin Rigo committed
475
476
        if pto.c_tp_doc:
            self.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
477
478
479

@bootstrap_function
def init_typeobject(space):
480
    make_typedescr(space.w_type.layout.typedef,
481
                   basestruct=PyTypeObject,
482
                   alloc=type_alloc,
483
484
485
486
                   attach=type_attach,
                   realize=type_realize,
                   dealloc=type_dealloc)

487
@cpython_api([PyObject], lltype.Void, header=None)
488
489
490
def subtype_dealloc(space, obj):
    pto = obj.c_ob_type
    base = pto
491
492
    this_func_ptr = llhelper(subtype_dealloc.api_func.functype,
            subtype_dealloc.api_func.get_wrapper(space))
493
494
495
496
497
498
499
500
501
502
    while base.c_tp_dealloc == this_func_ptr:
        base = base.c_tp_base
        assert base
    dealloc = base.c_tp_dealloc
    # XXX call tp_del if necessary
    generic_cpy_call(space, dealloc, obj)
    # XXX cpy decrefs the pto here but we do it in the base-dealloc
    # hopefully this does not clash with the memory model assumed in
    # extension modules

503
@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, header=None,
504
             error=CANNOT_FAIL)
505
def bf_segcount(space, w_obj, ref):
506
    if ref:
Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
507
        ref[0] = space.len_w(w_obj)
508
509
    return 1

Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
510
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
511
             header=None, error=-1)
512
def bf_getreadbuffer(space, w_buf, segment, ref):
513
    from rpython.rlib.buffer import StringBuffer
514
    if segment != 0:
Philip Jenvey's avatar
Philip Jenvey committed
515
        raise oefmt(space.w_SystemError,
516
                    "accessing non-existent segment")
517
    buf = space.readbuf_w(w_buf)
518
519
    if isinstance(buf, StringBuffer):
        return str_getreadbuffer(space, w_buf, segment, ref)
520
521
522
    address = buf.get_raw_address()
    ref[0] = address
    return len(buf)
523

Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
524
@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
525
             header=None, error=-1)
526
527
def bf_getcharbuffer(space, w_buf, segment, ref):
    return bf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
528

529
530
531
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
             header=None, error=-1)
def bf_getwritebuffer(space, w_buf, segment, ref):
532
    if segment != 0:
Philip Jenvey's avatar
Philip Jenvey committed
533
        raise oefmt(space.w_SystemError,
534
                    "accessing non-existent segment")
535
536
537
538
    buf = space.writebuf_w(w_buf)
    ref[0] = buf.get_raw_address()
    return len(buf)

539
540
541
542
543
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
             header=None, error=-1)
def str_getreadbuffer(space, w_str, segment, ref):
    from pypy.module.cpyext.bytesobject import PyString_AsString
    if segment != 0:
544
545
        raise oefmt(space.w_SystemError,
                    "accessing non-existent string segment")
546
547
548
549
550
551
    pyref = make_ref(space, w_str)
    ref[0] = PyString_AsString(space, pyref)
    # Stolen reference: the object has better exist somewhere else
    Py_DecRef(space, pyref)
    return space.len_w(w_str)

552
553
554
555
556
557
558
559
560
561
562
563
564
565
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
             header=None, error=-1)
def unicode_getreadbuffer(space, w_str, segment, ref):
    from pypy.module.cpyext.unicodeobject import (
                PyUnicode_AS_UNICODE, PyUnicode_GET_DATA_SIZE)
    if segment != 0:
        raise oefmt(space.w_SystemError,
                    "accessing non-existent unicode segment")
    pyref = make_ref(space, w_str)
    ref[0] = PyUnicode_AS_UNICODE(space, pyref)
    # Stolen reference: the object has better exist somewhere else
    Py_DecRef(space, pyref)
    return PyUnicode_GET_DATA_SIZE(space, w_str)

566
567
568
569
570
@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
             header=None, error=-1)
def str_getcharbuffer(space, w_buf, segment, ref):
    return str_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))

571
@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
572
             header=None, error=-1)
573
574
575
def buf_getreadbuffer(space, pyref, segment, ref):
    from pypy.module.cpyext.bufferobject import PyBufferObject
    if segment != 0:
Philip Jenvey's avatar
Philip Jenvey committed
576
        raise oefmt(space.w_SystemError,
577
                    "accessing non-existent buffer segment")
578
579
580
581
    py_buf = rffi.cast(PyBufferObject, pyref)
    ref[0] = py_buf.c_b_ptr
    return py_buf.c_b_size

582
583
584
585
@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
             header=None, error=-1)
def buf_getcharbuffer(space, w_buf, segment, ref):
    return buf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
586

587
588
def setup_buffer_procs(space, w_type, pto):
    bufspec = w_type.layout.typedef.buffer
589
590
    if bufspec is None and not space.is_w(w_type, space.w_unicode):
        # not a buffer, but let w_unicode be a read buffer
591
        return
Amaury Forgeot d'Arc's avatar
Amaury Forgeot d'Arc committed
592
593
    c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
    lltype.render_immortal(c_buf)
594
595
    c_buf.c_bf_getsegcount = llhelper(bf_segcount.api_func.functype,
                                      bf_segcount.api_func.get_wrapper(space))
596
597
598
    if space.is_w(w_type, space.w_str):
        # Special case: str doesn't support get_raw_address(), so we have a
        # custom get*buffer that instead gives the address of the char* in the
Ronan Lamy's avatar
Ronan Lamy committed
599
        # PyBytesObject*!
600
601
602
603
604
605
        c_buf.c_bf_getreadbuffer = llhelper(
            str_getreadbuffer.api_func.functype,
            str_getreadbuffer.api_func.get_wrapper(space))
        c_buf.c_bf_getcharbuffer = llhelper(
            str_getcharbuffer.api_func.functype,
            str_getcharbuffer.api_func.get_wrapper(space))
606
607
608
609
610
611
612
    elif space.is_w(w_type, space.w_unicode):
        # Special case: unicode doesn't support get_raw_address(), so we have a
        # custom get*buffer that instead gives the address of the char* in the
        # PyUnicodeObject*!
        c_buf.c_bf_getreadbuffer = llhelper(
            unicode_getreadbuffer.api_func.functype,
            unicode_getreadbuffer.api_func.get_wrapper(space))
613
614
615
616
617
618
619
620
621
622
623
    elif space.is_w(w_type, space.w_buffer):
        # Special case: we store a permanent address on the cpyext wrapper,
        # so we'll reuse that.
        # Note: we could instead store a permanent address on the buffer object,
        # and use get_raw_address()
        c_buf.c_bf_getreadbuffer = llhelper(
            buf_getreadbuffer.api_func.functype,
            buf_getreadbuffer.api_func.get_wrapper(space))
        c_buf.c_bf_getcharbuffer = llhelper(
            buf_getcharbuffer.api_func.functype,
            buf_getcharbuffer.api_func.get_wrapper(space))
624
625
626
627
628
629
630
631
632
633
    else:
        # use get_raw_address()
        c_buf.c_bf_getreadbuffer = llhelper(bf_getreadbuffer.api_func.functype,
                                    bf_getreadbuffer.api_func.get_wrapper(space))
        c_buf.c_bf_getcharbuffer = llhelper(bf_getcharbuffer.api_func.functype,
                                    bf_getcharbuffer.api_func.get_wrapper(space))
        if bufspec == 'read-write':
            c_buf.c_bf_getwritebuffer = llhelper(
                bf_getwritebuffer.api_func.functype,
                bf_getwritebuffer.api_func.get_wrapper(space))
634
    pto.c_tp_as_buffer = c_buf
635
    pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
636
    pto.c_tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER
637

638
@cpython_api([PyObject], lltype.Void, header=None)
639
def type_dealloc(space, obj):
Matti Picus's avatar
Matti Picus committed
640
    from pypy.module.cpyext.object import _dealloc
641
642
643
    obj_pto = rffi.cast(PyTypeObjectPtr, obj)
    base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
    Py_DecRef(space, obj_pto.c_tp_bases)
644
    Py_DecRef(space, obj_pto.c_tp_mro)
645
    Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
646
    Py_DecRef(space, obj_pto.c_tp_dict)
647
    if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
648
649
        heaptype = rffi.cast(PyHeapTypeObject, obj)
        Py_DecRef(space, heaptype.c_ht_name)
650
        Py_DecRef(space, base_pyo)
Matti Picus's avatar
Matti Picus committed
651
        _dealloc(space, obj)
652
653


654
def type_alloc(space, w_metatype, itemsize=0):
655
656
657
658
659
660
661
662
    metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
    # Don't increase refcount for non-heaptypes
    if metatype:
        flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
        if not flags & Py_TPFLAGS_HEAPTYPE:
            Py_DecRef(space, w_metatype)

    heaptype = lltype.malloc(PyHeapTypeObject.TO,
663
664
                             flavor='raw', zero=True,
                             add_memory_pressure=True)
665
666
    pto = heaptype.c_ht_type
    pto.c_ob_refcnt = 1
Armin Rigo's avatar
Armin Rigo committed
667
    pto.c_ob_pypy_link = 0
668
669
670
671
672
673
    pto.c_ob_type = metatype
    pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
    pto.c_tp_as_number = heaptype.c_as_number
    pto.c_tp_as_sequence = heaptype.c_as_sequence
    pto.c_tp_as_mapping = heaptype.c_as_mapping
    pto.c_tp_as_buffer = heaptype.c_as_buffer
Armin Rigo's avatar
Armin Rigo committed
674
675
    pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
    pto.c_tp_itemsize = 0
676

677
678
    return rffi.cast(PyObject, heaptype)

679
def type_attach(space, py_obj, w_type):
680
681
682
    """
    Fills a newly allocated PyTypeObject from an existing type.
    """
683
    from pypy.module.cpyext.object import PyObject_Free
684
685
686
687
688

    assert isinstance(w_type, W_TypeObject)

    pto = rffi.cast(PyTypeObjectPtr, py_obj)

689
    typedescr = get_typedescr(w_type.layout.typedef)
690
691

    # dealloc
Armin Rigo's avatar
Armin Rigo committed
692
693
694
695
696
697
698
699
    if space.gettypeobject(w_type.layout.typedef) is w_type:
        # only for the exact type, like 'space.w_tuple' or 'space.w_list'
        pto.c_tp_dealloc = typedescr.get_dealloc(space)
    else:
        # for all subtypes, use subtype_dealloc()
        pto.c_tp_dealloc = llhelper(
            subtype_dealloc.api_func.functype,
            subtype_dealloc.api_func.get_wrapper(space))
700
701
    if space.is_w(w_type, space.w_str):
        pto.c_tp_itemsize = 1
702
703
    elif space.is_w(w_type, space.w_tuple):
        pto.c_tp_itemsize = rffi.sizeof(PyObject)
704
    # buffer protocol
705
    setup_buffer_procs(space, w_type, pto)
706

707
708
    pto.c_tp_free = llhelper(PyObject_Free.api_func.functype,
            PyObject_Free.api_func.get_wrapper(space))
709
710
    pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
            PyType_GenericAlloc.api_func.get_wrapper(space))
Armin Rigo's avatar
fix    
Armin Rigo committed
711
712
713
714
715
716
717
    builder = space.fromcache(StaticObjectBuilder)
    if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0
            and builder.cpyext_type_init is None):
            # this ^^^ is not None only during startup of cpyext.  At that
            # point we might get into troubles by doing make_ref() when
            # things are not initialized yet.  So in this case, simply use
            # str2charp() and "leak" the string.
718
719
720
        w_typename = space.getattr(w_type, space.wrap('__name__'))
        heaptype = rffi.cast(PyHeapTypeObject, pto)
        heaptype.c_ht_name = make_ref(space, w_typename)
Matti Picus's avatar
Matti Picus committed
721
        from pypy.module.cpyext.bytesobject import PyString_AsString
722
723
        pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name)
    else:
Brian Kearns's avatar
Brian Kearns committed
724
        pto.c_tp_name = rffi.str2charp(w_type.name)
725
    # uninitialized fields:
726
    # c_tp_print
727
    # XXX implement
728
    # c_tp_compare and more?
729
730
731
    w_base = best_base(space, w_type.bases_w)
    pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))

Armin Rigo's avatar
Armin Rigo committed
732
733
    if builder.cpyext_type_init is not None:
        builder.cpyext_type_init.append((pto, w_type))
734
735
736
    else:
        finish_type_1(space, pto)
        finish_type_2(space, pto, w_type)
737
738
739
740
741

    pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
    if pto.c_tp_base:
        if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
            pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
742
743
        if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize:
            pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize
744
745
746
747
748
749

    # will be filled later on with the correct value
    # may not be 0
    if space.is_w(w_type, space.w_object):
        pto.c_tp_new = rffi.cast(newfunc, 1)
    update_all_slots(space, w_type, pto)
750
751
752
753
754
755
756
    if not pto.c_tp_new:
        base_object_pyo = make_ref(space, space.w_object)
        base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
        flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
        if pto.c_tp_base != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
                pto.c_tp_new = pto.c_tp_base.c_tp_new
        Py_DecRef(space, base_object_pyo)
757
    pto.c_tp_flags |= Py_TPFLAGS_READY
758
759
    return pto

760
def py_type_ready(space, pto):
761
    if pto.c_tp_flags & Py_TPFLAGS_READY:
762
        return
763
    type_realize(space, rffi.cast(PyObject, pto))
764
765
766
767

@cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
def PyType_Ready(space, pto):
    py_type_ready(space, pto)
768
769
770
771
    return 0

def type_realize(space, py_obj):
    pto = rffi.cast(PyTypeObjectPtr, py_obj)
772
    assert pto.c_tp_flags & Py_TPFLAGS_READY == 0
773
774
775
    assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
    pto.c_tp_flags |= Py_TPFLAGS_READYING
    try:
776
        w_obj = _type_realize(space, py_obj)
777
    finally:
778
        name = rffi.charp2str(pto.c_tp_name)
779
        pto.c_tp_flags &= ~Py_TPFLAGS_READYING
780
781
    pto.c_tp_flags |= Py_TPFLAGS_READY
    return w_obj
782
783

def solid_base(space, w_type):
784
    typedef = w_type.layout.typedef
785
786
787
788
789
    return space.gettypeobject(typedef)

def best_base(space, bases_w):
    if not bases_w:
        return None
Armin Rigo's avatar
Armin Rigo committed
790
    return find_best_base(bases_w)
791
792
793
794
795
796
797

def inherit_slots(space, pto, w_base):
    base_pyo = make_ref(space, w_base)
    try:
        base = rffi.cast(PyTypeObjectPtr, base_pyo)
        if not pto.c_tp_dealloc:
            pto.c_tp_dealloc = base.c_tp_dealloc
798
799
        if not pto.c_tp_init:
            pto.c_tp_init = base.c_tp_init
Jan de Mooij's avatar
Jan de Mooij committed
800
801
        if not pto.c_tp_alloc:
            pto.c_tp_alloc = base.c_tp_alloc
802
803
804
        # XXX check for correct GC flags!
        if not pto.c_tp_free:
            pto.c_tp_free = base.c_tp_free
805
806
        if not pto.c_tp_setattro:
            pto.c_tp_setattro = base.c_tp_setattro
807
808
        if not pto.c_tp_getattro:
            pto.c_tp_getattro = base.c_tp_getattro
809
810
        if not pto.c_tp_as_buffer:
            pto.c_tp_as_buffer = base.c_tp_as_buffer
811
        if base.c_tp_as_buffer:
812
            # inherit base.c_tp_as_buffer functions not inherited from w_type
813
            # note: builtin types are handled in setup_buffer_procs
814
815
            pto_as = pto.c_tp_as_buffer
            base_as = base.c_tp_as_buffer
816
817
818
819
            if not pto_as.c_bf_getbuffer:
                pto_as.c_bf_getbuffer = base_as.c_bf_getbuffer
            if not pto_as.c_bf_getcharbuffer:
                pto_as.c_bf_getcharbuffer = base_as.c_bf_getcharbuffer
820
821
            if not pto_as.c_bf_getwritebuffer:
                pto_as.c_bf_getwritebuffer = base_as.c_bf_getwritebuffer
822
823
            if not pto_as.c_bf_getreadbuffer:
                pto_as.c_bf_getreadbuffer = base_as.c_bf_getreadbuffer
824
825
            if not pto_as.c_bf_getsegcount:
                pto_as.c_bf_getsegcount = base_as.c_bf_getsegcount
826
            if not pto_as.c_bf_releasebuffer:
827
                pto_as.c_bf_releasebuffer = base_as.c_bf_releasebuffer
828
829
830
    finally:
        Py_DecRef(space, base_pyo)

831
def _type_realize(space, py_obj):
832
833
834
    """
    Creates an interpreter type from a PyTypeObject structure.
    """
835
836
837
838
    # missing:
    # unsupported:
    # tp_mro, tp_subclasses
    py_type = rffi.cast(PyTypeObjectPtr, py_obj)
839

840
    if not py_type.c_tp_base:
841
        # borrowed reference, but w_object is unlikely to disappear
842
        base = as_pyobj(space, space.w_object)
843
844
845
        py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)

    finish_type_1(space, py_type)
846

847
848
    if py_type.c_ob_type:
        w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
Ronan Lamy's avatar
Ronan Lamy committed
849
    else:
850
851
852
853
        # Somehow the tp_base type is created with no ob_type, notably
        # PyString_Type and PyBaseString_Type
        # While this is a hack, cpython does it as well.
        w_metatype = space.w_type
854
855

    w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
856
    track_reference(space, py_obj, w_obj)
857
858
    # __init__ wraps all slotdefs functions from py_type via add_operators
    w_obj.__init__(space, py_type) 
859
860
861
    w_obj.ready()

    finish_type_2(space, py_type, w_obj)
862
863
    base = py_type.c_tp_base
    if base:
864
        # XXX refactor - parts of this are done in finish_type_2 -> inherit_slots
865
866
867
868
869
870
871
        if not py_type.c_tp_as_number: 
            py_type.c_tp_as_number = base.c_tp_as_number
            py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_CHECKTYPES
            py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
        if not py_type.c_tp_as_sequence:
            py_type.c_tp_as_sequence = base.c_tp_as_sequence
            py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
Ronan Lamy's avatar
Ronan Lamy committed
872
        if not py_type.c_tp_as_mapping: py_type.c_tp_as_mapping = base.c_tp_as_mapping
873
        #if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer
874

875
    return w_obj
876

877
878
879
880
881
882
883
def finish_type_1(space, pto):
    """
    Sets up tp_bases, necessary before creating the interpreter type.
    """
    base = pto.c_tp_base
    base_pyo = rffi.cast(PyObject, pto.c_tp_base)
    if base and not base.c_tp_flags & Py_TPFLAGS_READY:
884
885
        name = rffi.charp2str(base.c_tp_name)
        type_realize(space, base_pyo)
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
    if base and not pto.c_ob_type: # will be filled later
        pto.c_ob_type = base.c_ob_type
    if not pto.c_tp_bases:
        if not base:
            bases = space.newtuple([])
        else:
            bases = space.newtuple([from_ref(space, base_pyo)])
        pto.c_tp_bases = make_ref(space, bases)

def finish_type_2(space, pto, w_obj):
    """
    Sets up other attributes, when the interpreter type has been created.
    """
    pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
    base = pto.c_tp_base
    if base:
        inherit_special(space, pto, base)
    for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
        inherit_slots(space, pto, w_base)

906
907
908
909
910
911
    if not pto.c_tp_setattro:
        from pypy.module.cpyext.object import PyObject_GenericSetAttr
        pto.c_tp_setattro = llhelper(
            PyObject_GenericSetAttr.api_func.functype,
            PyObject_GenericSetAttr.api_func.get_wrapper(space))

912
913
914
915
916
917
    if not pto.c_tp_getattro:
        from pypy.module.cpyext.object import PyObject_GenericGetAttr
        pto.c_tp_getattro = llhelper(
            PyObject_GenericGetAttr.api_func.functype,
            PyObject_GenericGetAttr.api_func.get_wrapper(space))

918
919
    if w_obj.is_cpytype():
        Py_DecRef(space, pto.c_tp_dict)
920
921
    w_dict = w_obj.getdict(space)
    pto.c_tp_dict = make_ref(space, w_dict)
922

923
924
925
926
927
928
929
930
@cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
def PyType_IsSubtype(space, a, b):
    """Return true if a is a subtype of b.
    """
    w_type1 = from_ref(space, rffi.cast(PyObject, a))
    w_type2 = from_ref(space, rffi.cast(PyObject, b))
    return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?

Armin Rigo's avatar
Armin Rigo committed
931
@cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject, result_is_ll=True)
932
933
934
935
def PyType_GenericAlloc(space, type, nitems):
    from pypy.module.cpyext.object import _PyObject_NewVar
    return _PyObject_NewVar(space, type, nitems)

936
937
938
939
940
@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
def PyType_GenericNew(space, type, w_args, w_kwds):
    return generic_cpy_call(
        space, type.c_tp_alloc, type, 0)

Armin Rigo's avatar
Armin Rigo committed
941
942
@cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL,
             result_borrowed=True)
943
944
945
def _PyType_Lookup(space, type, w_name):
    """Internal API to look for a name through the MRO.
    This returns a borrowed reference, and doesn't set an exception!"""
946
    w_type = from_ref(space, rffi.cast(PyObject, type))
947
    assert isinstance(w_type, W_TypeObject)
948
949
950

    if not space.isinstance_w(w_name, space.w_str):
        return None
951
952
    name = space.str_w(w_name)
    w_obj = w_type.lookup(name)
Armin Rigo's avatar
Armin Rigo committed
953
    # this assumes that w_obj is not dynamically created, but will stay alive
954
    # until w_type is modified or dies.  Assuming this, we return a borrowed ref
Armin Rigo's avatar
Armin Rigo committed
955
    return w_obj
956
957
958
959
960
961
962

@cpython_api([PyTypeObjectPtr], lltype.Void)
def PyType_Modified(space, w_obj):
    """Invalidate the internal lookup cache for the type and all of its
    subtypes.  This function must be called after any manual
    modification of the attributes or base classes of the type.
    """
963
964
965
966
967
    # Invalidate the type cache in case of a builtin type.
    if not isinstance(w_obj, W_TypeObject):
        return
    if w_obj.is_cpytype():
        w_obj.mutated(None)
968