/pypy/module/cpyext/typeobject.py
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