/pypy/module/cpyext/typeobject.py
Python | 911 lines | 722 code | 98 blank | 91 comment | 121 complexity | 2676b0ac75c12fc8543bb9fb53ce2649 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
1import os
2
3from rpython.rlib import jit
4from rpython.rlib.objectmodel import specialize
5from rpython.rlib.rstring import rsplit
6from rpython.rtyper.annlowlevel import llhelper
7from rpython.rtyper.lltypesystem import rffi, lltype
8
9from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
10from pypy.interpreter.error import oefmt
11from pypy.interpreter.typedef import (GetSetProperty, TypeDef,
12 interp_attrproperty, interp_attrproperty, interp2app)
13from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
14from pypy.module.cpyext import structmemberdefs
15from pypy.module.cpyext.api import (
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,
19 Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder,
20 PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr)
21from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
22 W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
23 W_PyCMethodObject, W_PyCFunctionObject)
24from pypy.module.cpyext.modsupport import convert_method_defs
25from pypy.module.cpyext.pyobject import (
26 PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
27 track_reference, Py_DecRef, as_pyobj)
28from pypy.module.cpyext.slotdefs import (
29 slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
30from pypy.module.cpyext.state import State
31from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
32from pypy.module.cpyext.typeobjectdefs import (
33 PyGetSetDef, PyMemberDef, newfunc,
34 PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
35from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
36
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 name = 'member_descriptor'
76 def __init__(self, member, w_type):
77 self.member = member
78 self.name = rffi.charp2str(member.c_name)
79 self.w_type = w_type
80 flags = rffi.cast(lltype.Signed, member.c_flags)
81 doc = set = None
82 if member.c_doc:
83 doc = rffi.charp2str(member.c_doc)
84 get = GettersAndSetters.member_getter.im_func
85 del_ = GettersAndSetters.member_delete.im_func
86 if not (flags & structmemberdefs.READONLY):
87 set = GettersAndSetters.member_setter.im_func
88 GetSetProperty.__init__(self, get, set, del_, doc,
89 cls=None, use_closure=True,
90 tag="cpyext_2")
91
92# change the typedef name
93W_MemberDescr.typedef = TypeDef(
94 "member_descriptor",
95 __get__ = interp2app(GetSetProperty.descr_property_get),
96 __set__ = interp2app(GetSetProperty.descr_property_set),
97 __delete__ = interp2app(GetSetProperty.descr_property_del),
98 __name__ = interp_attrproperty('name', cls=GetSetProperty),
99 __objclass__ = GetSetProperty(GetSetProperty.descr_get_objclass),
100 __doc__ = interp_attrproperty('doc', cls=GetSetProperty),
101 )
102assert not W_MemberDescr.typedef.acceptable_as_base_class # no __new__
103
104PyDescrObject = lltype.ForwardReference()
105PyDescrObjectPtr = lltype.Ptr(PyDescrObject)
106PyDescrObjectFields = PyObjectFields + (
107 ("d_type", PyTypeObjectPtr),
108 ("d_name", PyObject),
109 )
110cpython_struct("PyDescrObject", PyDescrObjectFields,
111 PyDescrObject)
112
113PyMemberDescrObjectStruct = lltype.ForwardReference()
114PyMemberDescrObject = lltype.Ptr(PyMemberDescrObjectStruct)
115PyMemberDescrObjectFields = PyDescrObjectFields + (
116 ("d_member", lltype.Ptr(PyMemberDef)),
117 )
118cpython_struct("PyMemberDescrObject", PyMemberDescrObjectFields,
119 PyMemberDescrObjectStruct, level=2)
120
121PyGetSetDescrObjectStruct = lltype.ForwardReference()
122PyGetSetDescrObject = lltype.Ptr(PyGetSetDescrObjectStruct)
123PyGetSetDescrObjectFields = PyDescrObjectFields + (
124 ("d_getset", lltype.Ptr(PyGetSetDef)),
125 )
126cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields,
127 PyGetSetDescrObjectStruct, level=2)
128
129PyMethodDescrObjectStruct = lltype.ForwardReference()
130PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct)
131PyMethodDescrObjectFields = PyDescrObjectFields + (
132 ("d_method", lltype.Ptr(PyMethodDef)),
133 )
134cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields,
135 PyMethodDescrObjectStruct, level=2)
136
137@bootstrap_function
138def init_memberdescrobject(space):
139 make_typedescr(W_MemberDescr.typedef,
140 basestruct=PyMemberDescrObject.TO,
141 attach=memberdescr_attach,
142 realize=memberdescr_realize,
143 )
144 make_typedescr(W_GetSetPropertyEx.typedef,
145 basestruct=PyGetSetDescrObject.TO,
146 attach=getsetdescr_attach,
147 )
148 make_typedescr(W_PyCClassMethodObject.typedef,
149 basestruct=PyMethodDescrObject.TO,
150 attach=methoddescr_attach,
151 realize=classmethoddescr_realize,
152 )
153 make_typedescr(W_PyCMethodObject.typedef,
154 basestruct=PyMethodDescrObject.TO,
155 attach=methoddescr_attach,
156 realize=methoddescr_realize,
157 )
158
159def memberdescr_attach(space, py_obj, w_obj):
160 """
161 Fills a newly allocated PyMemberDescrObject with the given W_MemberDescr
162 object. The values must not be modified.
163 """
164 py_memberdescr = rffi.cast(PyMemberDescrObject, py_obj)
165 # XXX assign to d_dname, d_type?
166 assert isinstance(w_obj, W_MemberDescr)
167 py_memberdescr.c_d_member = w_obj.member
168
169def memberdescr_realize(space, obj):
170 # XXX NOT TESTED When is this ever called?
171 member = rffi.cast(lltype.Ptr(PyMemberDef), obj)
172 w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
173 w_obj = space.allocate_instance(W_MemberDescr, w_type)
174 w_obj.__init__(member, w_type)
175 track_reference(space, obj, w_obj)
176 return w_obj
177
178def getsetdescr_attach(space, py_obj, w_obj):
179 """
180 Fills a newly allocated PyGetSetDescrObject with the given W_GetSetPropertyEx
181 object. The values must not be modified.
182 """
183 py_getsetdescr = rffi.cast(PyGetSetDescrObject, py_obj)
184 # XXX assign to d_dname, d_type?
185 assert isinstance(w_obj, W_GetSetPropertyEx)
186 py_getsetdescr.c_d_getset = w_obj.getset
187
188def methoddescr_attach(space, py_obj, w_obj):
189 py_methoddescr = rffi.cast(PyMethodDescrObject, py_obj)
190 # XXX assign to d_dname, d_type?
191 assert isinstance(w_obj, W_PyCFunctionObject)
192 py_methoddescr.c_d_method = w_obj.ml
193
194def classmethoddescr_realize(space, obj):
195 # XXX NOT TESTED When is this ever called?
196 method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
197 w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
198 w_obj = space.allocate_instance(W_PyCClassMethodObject, w_type)
199 w_obj.__init__(space, method, w_type)
200 track_reference(space, obj, w_obj)
201 return w_obj
202
203def methoddescr_realize(space, obj):
204 # XXX NOT TESTED When is this ever called?
205 method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
206 w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
207 w_obj = space.allocate_instance(W_PyCMethodObject, w_type)
208 w_obj.__init__(space, method, w_type)
209 track_reference(space, obj, w_obj)
210 return w_obj
211
212def convert_getset_defs(space, dict_w, getsets, w_type):
213 getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
214 if getsets:
215 i = -1
216 while True:
217 i = i + 1
218 getset = getsets[i]
219 name = getset.c_name
220 if not name:
221 break
222 name = rffi.charp2str(name)
223 w_descr = PyDescr_NewGetSet(space, getset, w_type)
224 dict_w[name] = w_descr
225
226def convert_member_defs(space, dict_w, members, w_type):
227 members = rffi.cast(rffi.CArrayPtr(PyMemberDef), members)
228 if members:
229 i = 0
230 while True:
231 member = members[i]
232 name = member.c_name
233 if not name:
234 break
235 name = rffi.charp2str(name)
236 w_descr = space.wrap(W_MemberDescr(member, w_type))
237 dict_w[name] = w_descr
238 i += 1
239
240def update_all_slots(space, w_type, pto):
241 # fill slots in pto
242 # Not very sure about it, but according to
243 # test_call_tp_dealloc_when_created_from_python, we should not
244 # overwrite slots that are already set: these ones are probably
245 # coming from a parent C type.
246
247 typedef = w_type.layout.typedef
248 for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
249 w_descr = w_type.lookup(method_name)
250 if w_descr is None:
251 # XXX special case iternext
252 continue
253
254 slot_func_helper = None
255
256 if slot_func is None and typedef is not None:
257 get_slot = get_slot_tp_function(space, typedef, slot_name)
258 if get_slot:
259 slot_func_helper = get_slot()
260 elif slot_func:
261 slot_func_helper = llhelper(slot_func.api_func.functype,
262 slot_func.api_func.get_wrapper(space))
263
264 if slot_func_helper is None:
265 if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
266 os.write(2, "%s defined by %s but no slot function defined!\n" % (
267 method_name, w_type.getname(space)))
268 continue
269
270 # XXX special case wrapper-functions and use a "specific" slot func
271
272 if len(slot_names) == 1:
273 if not getattr(pto, slot_names[0]):
274 setattr(pto, slot_names[0], slot_func_helper)
275 elif (w_type.getname(space) in ('list', 'tuple') and
276 slot_names[0] == 'c_tp_as_number'):
277 # XXX hack - hwo can we generalize this? The problem is method
278 # names like __mul__ map to more than one slot, and we have no
279 # convenient way to indicate which slots CPython have filled
280 #
281 # We need at least this special case since Numpy checks that
282 # (list, tuple) do __not__ fill tp_as_number
283 pass
284 else:
285 assert len(slot_names) == 2
286 struct = getattr(pto, slot_names[0])
287 if not struct:
288 #assert not space.config.translating
289 assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
290 if slot_names[0] == 'c_tp_as_number':
291 STRUCT_TYPE = PyNumberMethods
292 elif slot_names[0] == 'c_tp_as_sequence':
293 STRUCT_TYPE = PySequenceMethods
294 else:
295 raise AssertionError(
296 "Structure not allocated: %s" % (slot_names[0],))
297 struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
298 setattr(pto, slot_names[0], struct)
299
300 if not getattr(struct, slot_names[1]):
301 setattr(struct, slot_names[1], slot_func_helper)
302
303def add_operators(space, dict_w, pto):
304 # XXX support PyObject_HashNotImplemented
305 for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
306 if method_name in dict_w:
307 continue
308 offset = [rffi.offsetof(lltype.typeOf(pto).TO, slot_names[0])]
309 if len(slot_names) == 1:
310 func = getattr(pto, slot_names[0])
311 else:
312 assert len(slot_names) == 2
313 struct = getattr(pto, slot_names[0])
314 if not struct:
315 continue
316 offset.append(rffi.offsetof(lltype.typeOf(struct).TO, slot_names[1]))
317 func = getattr(struct, slot_names[1])
318 func_voidp = rffi.cast(rffi.VOIDP, func)
319 if not func:
320 continue
321 if wrapper_func is None and wrapper_func_kwds is None:
322 continue
323 w_obj = W_PyCWrapperObject(space, pto, method_name, wrapper_func,
324 wrapper_func_kwds, doc, func_voidp, offset=offset)
325 dict_w[method_name] = space.wrap(w_obj)
326 if pto.c_tp_new:
327 add_tp_new_wrapper(space, dict_w, pto)
328
329@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None)
330def tp_new_wrapper(space, self, w_args, w_kwds):
331 self_pytype = rffi.cast(PyTypeObjectPtr, self)
332 tp_new = self_pytype.c_tp_new
333
334 # Check that the user doesn't do something silly and unsafe like
335 # object.__new__(dict). To do this, we check that the most
336 # derived base that's not a heap type is this type.
337 # XXX do it
338
339 args_w = space.fixedview(w_args)
340 w_subtype = args_w[0]
341 w_args = space.newtuple(args_w[1:])
342 if not space.is_true(w_kwds):
343 w_kwds = None
344
345 try:
346 subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
347 w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
348 finally:
349 Py_DecRef(space, w_subtype)
350 return w_obj
351
352@specialize.memo()
353def get_new_method_def(space):
354 state = space.fromcache(State)
355 if state.new_method_def:
356 return state.new_method_def
357 ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
358 immortal=True)
359 ptr.c_ml_name = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp("__new__"))
360 lltype.render_immortal(ptr.c_ml_name)
361 rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
362 ptr.c_ml_doc = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp(
363 "T.__new__(S, ...) -> a new object with type S, a subtype of T"))
364 lltype.render_immortal(ptr.c_ml_doc)
365 state.new_method_def = ptr
366 return ptr
367
368def setup_new_method_def(space):
369 ptr = get_new_method_def(space)
370 ptr.c_ml_meth = rffi.cast(PyCFunction_typedef,
371 llhelper(tp_new_wrapper.api_func.functype,
372 tp_new_wrapper.api_func.get_wrapper(space)))
373
374def add_tp_new_wrapper(space, dict_w, pto):
375 if "__new__" in dict_w:
376 return
377 pyo = rffi.cast(PyObject, pto)
378 dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
379 from_ref(space, pyo), None)
380
381def inherit_special(space, pto, base_pto):
382 # XXX missing: copy basicsize and flags in a magical way
383 # (minimally, if tp_basicsize is zero we copy it from the base)
384 if not pto.c_tp_basicsize:
385 pto.c_tp_basicsize = base_pto.c_tp_basicsize
386 if pto.c_tp_itemsize < base_pto.c_tp_itemsize:
387 pto.c_tp_itemsize = base_pto.c_tp_itemsize
388 flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
389 base_object_pyo = make_ref(space, space.w_object)
390 base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
391 if base_pto != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
392 if not pto.c_tp_new:
393 pto.c_tp_new = base_pto.c_tp_new
394 Py_DecRef(space, base_object_pyo)
395
396def check_descr(space, w_self, w_type):
397 if not space.isinstance_w(w_self, w_type):
398 raise DescrMismatch()
399
400class GettersAndSetters:
401 def getter(self, space, w_self):
402 assert isinstance(self, W_GetSetPropertyEx)
403 check_descr(space, w_self, self.w_type)
404 return generic_cpy_call(
405 space, self.getset.c_get, w_self,
406 self.getset.c_closure)
407
408 def setter(self, space, w_self, w_value):
409 assert isinstance(self, W_GetSetPropertyEx)
410 check_descr(space, w_self, self.w_type)
411 res = generic_cpy_call(
412 space, self.getset.c_set, w_self, w_value,
413 self.getset.c_closure)
414 if rffi.cast(lltype.Signed, res) < 0:
415 state = space.fromcache(State)
416 state.check_and_raise_exception()
417
418 def member_getter(self, space, w_self):
419 assert isinstance(self, W_MemberDescr)
420 check_descr(space, w_self, self.w_type)
421 pyref = make_ref(space, w_self)
422 try:
423 return PyMember_GetOne(
424 space, rffi.cast(rffi.CCHARP, pyref), self.member)
425 finally:
426 Py_DecRef(space, pyref)
427
428 def member_delete(self, space, w_self):
429 assert isinstance(self, W_MemberDescr)
430 check_descr(space, w_self, self.w_type)
431 pyref = make_ref(space, w_self)
432 try:
433 PyMember_SetOne(
434 space, rffi.cast(rffi.CCHARP, pyref), self.member, None)
435 finally:
436 Py_DecRef(space, pyref)
437
438 def member_setter(self, space, w_self, w_value):
439 assert isinstance(self, W_MemberDescr)
440 check_descr(space, w_self, self.w_type)
441 pyref = make_ref(space, w_self)
442 try:
443 PyMember_SetOne(
444 space, rffi.cast(rffi.CCHARP, pyref), self.member, w_value)
445 finally:
446 Py_DecRef(space, pyref)
447
448class W_PyCTypeObject(W_TypeObject):
449 @jit.dont_look_inside
450 def __init__(self, space, pto):
451 bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
452 dict_w = {}
453
454 add_operators(space, dict_w, pto)
455 convert_method_defs(space, dict_w, pto.c_tp_methods, self)
456 convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
457 convert_member_defs(space, dict_w, pto.c_tp_members, self)
458
459 name = rffi.charp2str(pto.c_tp_name)
460 new_layout = (pto.c_tp_basicsize > rffi.sizeof(PyObject.TO) or
461 pto.c_tp_itemsize > 0)
462
463 W_TypeObject.__init__(self, space, name,
464 bases_w or [space.w_object], dict_w, force_new_layout=new_layout)
465 self.flag_cpytype = True
466 self.flag_heaptype = False
467 # if a sequence or a mapping, then set the flag to force it
468 if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
469 self.flag_map_or_seq = 'S'
470 elif (pto.c_tp_as_mapping and pto.c_tp_as_mapping.c_mp_subscript and
471 not (pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_slice)):
472 self.flag_map_or_seq = 'M'
473 if pto.c_tp_doc:
474 self.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
475
476@bootstrap_function
477def init_typeobject(space):
478 make_typedescr(space.w_type.layout.typedef,
479 basestruct=PyTypeObject,
480 alloc=type_alloc,
481 attach=type_attach,
482 realize=type_realize,
483 dealloc=type_dealloc)
484
485@cpython_api([PyObject], lltype.Void, header=None)
486def subtype_dealloc(space, obj):
487 pto = obj.c_ob_type
488 base = pto
489 this_func_ptr = llhelper(subtype_dealloc.api_func.functype,
490 subtype_dealloc.api_func.get_wrapper(space))
491 while base.c_tp_dealloc == this_func_ptr:
492 base = base.c_tp_base
493 assert base
494 dealloc = base.c_tp_dealloc
495 # XXX call tp_del if necessary
496 generic_cpy_call(space, dealloc, obj)
497 # XXX cpy decrefs the pto here but we do it in the base-dealloc
498 # hopefully this does not clash with the memory model assumed in
499 # extension modules
500
501@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, header=None,
502 error=CANNOT_FAIL)
503def bf_segcount(space, w_obj, ref):
504 if ref:
505 ref[0] = space.len_w(w_obj)
506 return 1
507
508@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
509 header=None, error=-1)
510def bf_getreadbuffer(space, w_buf, segment, ref):
511 if segment != 0:
512 raise oefmt(space.w_SystemError,
513 "accessing non-existent segment")
514 buf = space.readbuf_w(w_buf)
515 address = buf.get_raw_address()
516 ref[0] = address
517 return len(buf)
518
519@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
520 header=None, error=-1)
521def bf_getcharbuffer(space, w_buf, segment, ref):
522 return bf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
523
524@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
525 header=None, error=-1)
526def bf_getwritebuffer(space, w_buf, segment, ref):
527 if segment != 0:
528 raise oefmt(space.w_SystemError,
529 "accessing non-existent segment")
530
531 buf = space.writebuf_w(w_buf)
532 ref[0] = buf.get_raw_address()
533 return len(buf)
534
535@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
536 header=None, error=-1)
537def str_getreadbuffer(space, w_str, segment, ref):
538 from pypy.module.cpyext.bytesobject import PyString_AsString
539 if segment != 0:
540 raise oefmt(space.w_SystemError,
541 "accessing non-existent string segment")
542 pyref = make_ref(space, w_str)
543 ref[0] = PyString_AsString(space, pyref)
544 # Stolen reference: the object has better exist somewhere else
545 Py_DecRef(space, pyref)
546 return space.len_w(w_str)
547
548@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
549 header=None, error=-1)
550def str_getcharbuffer(space, w_buf, segment, ref):
551 return str_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
552
553@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
554 header=None, error=-1)
555def buf_getreadbuffer(space, pyref, segment, ref):
556 from pypy.module.cpyext.bufferobject import PyBufferObject
557 if segment != 0:
558 raise oefmt(space.w_SystemError,
559 "accessing non-existent buffer segment")
560 py_buf = rffi.cast(PyBufferObject, pyref)
561 ref[0] = py_buf.c_b_ptr
562 return py_buf.c_b_size
563
564@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
565 header=None, error=-1)
566def buf_getcharbuffer(space, w_buf, segment, ref):
567 return buf_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
568
569def setup_buffer_procs(space, w_type, pto):
570 bufspec = w_type.layout.typedef.buffer
571 if bufspec is None:
572 # not a buffer
573 return
574 c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
575 lltype.render_immortal(c_buf)
576 c_buf.c_bf_getsegcount = llhelper(bf_segcount.api_func.functype,
577 bf_segcount.api_func.get_wrapper(space))
578 if space.is_w(w_type, space.w_str):
579 # Special case: str doesn't support get_raw_address(), so we have a
580 # custom get*buffer that instead gives the address of the char* in the
581 # PyBytesObject*!
582 c_buf.c_bf_getreadbuffer = llhelper(
583 str_getreadbuffer.api_func.functype,
584 str_getreadbuffer.api_func.get_wrapper(space))
585 c_buf.c_bf_getcharbuffer = llhelper(
586 str_getcharbuffer.api_func.functype,
587 str_getcharbuffer.api_func.get_wrapper(space))
588 elif space.is_w(w_type, space.w_buffer):
589 # Special case: we store a permanent address on the cpyext wrapper,
590 # so we'll reuse that.
591 # Note: we could instead store a permanent address on the buffer object,
592 # and use get_raw_address()
593 c_buf.c_bf_getreadbuffer = llhelper(
594 buf_getreadbuffer.api_func.functype,
595 buf_getreadbuffer.api_func.get_wrapper(space))
596 c_buf.c_bf_getcharbuffer = llhelper(
597 buf_getcharbuffer.api_func.functype,
598 buf_getcharbuffer.api_func.get_wrapper(space))
599 else:
600 # use get_raw_address()
601 c_buf.c_bf_getreadbuffer = llhelper(bf_getreadbuffer.api_func.functype,
602 bf_getreadbuffer.api_func.get_wrapper(space))
603 c_buf.c_bf_getcharbuffer = llhelper(bf_getcharbuffer.api_func.functype,
604 bf_getcharbuffer.api_func.get_wrapper(space))
605 if bufspec == 'read-write':
606 c_buf.c_bf_getwritebuffer = llhelper(
607 bf_getwritebuffer.api_func.functype,
608 bf_getwritebuffer.api_func.get_wrapper(space))
609 pto.c_tp_as_buffer = c_buf
610 pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
611
612@cpython_api([PyObject], lltype.Void, header=None)
613def type_dealloc(space, obj):
614 from pypy.module.cpyext.object import _dealloc
615 obj_pto = rffi.cast(PyTypeObjectPtr, obj)
616 base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
617 Py_DecRef(space, obj_pto.c_tp_bases)
618 Py_DecRef(space, obj_pto.c_tp_mro)
619 Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
620 Py_DecRef(space, obj_pto.c_tp_dict)
621 if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
622 heaptype = rffi.cast(PyHeapTypeObject, obj)
623 Py_DecRef(space, heaptype.c_ht_name)
624 Py_DecRef(space, base_pyo)
625 _dealloc(space, obj)
626
627
628def type_alloc(space, w_metatype, itemsize=0):
629 metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
630 # Don't increase refcount for non-heaptypes
631 if metatype:
632 flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
633 if not flags & Py_TPFLAGS_HEAPTYPE:
634 Py_DecRef(space, w_metatype)
635
636 heaptype = lltype.malloc(PyHeapTypeObject.TO,
637 flavor='raw', zero=True,
638 add_memory_pressure=True)
639 pto = heaptype.c_ht_type
640 pto.c_ob_refcnt = 1
641 pto.c_ob_pypy_link = 0
642 pto.c_ob_type = metatype
643 pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
644 pto.c_tp_as_number = heaptype.c_as_number
645 pto.c_tp_as_sequence = heaptype.c_as_sequence
646 pto.c_tp_as_mapping = heaptype.c_as_mapping
647 pto.c_tp_as_buffer = heaptype.c_as_buffer
648 pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
649 pto.c_tp_itemsize = 0
650
651 return rffi.cast(PyObject, heaptype)
652
653def type_attach(space, py_obj, w_type):
654 """
655 Fills a newly allocated PyTypeObject from an existing type.
656 """
657 from pypy.module.cpyext.object import PyObject_Free
658
659 assert isinstance(w_type, W_TypeObject)
660
661 pto = rffi.cast(PyTypeObjectPtr, py_obj)
662
663 typedescr = get_typedescr(w_type.layout.typedef)
664
665 # dealloc
666 if space.gettypeobject(w_type.layout.typedef) is w_type:
667 # only for the exact type, like 'space.w_tuple' or 'space.w_list'
668 pto.c_tp_dealloc = typedescr.get_dealloc(space)
669 else:
670 # for all subtypes, use subtype_dealloc()
671 pto.c_tp_dealloc = llhelper(
672 subtype_dealloc.api_func.functype,
673 subtype_dealloc.api_func.get_wrapper(space))
674 if space.is_w(w_type, space.w_str):
675 pto.c_tp_itemsize = 1
676 elif space.is_w(w_type, space.w_tuple):
677 pto.c_tp_itemsize = rffi.sizeof(PyObject)
678 # buffer protocol
679 setup_buffer_procs(space, w_type, pto)
680
681 pto.c_tp_free = llhelper(PyObject_Free.api_func.functype,
682 PyObject_Free.api_func.get_wrapper(space))
683 pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
684 PyType_GenericAlloc.api_func.get_wrapper(space))
685 builder = space.fromcache(StaticObjectBuilder)
686 if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0
687 and builder.cpyext_type_init is None):
688 # this ^^^ is not None only during startup of cpyext. At that
689 # point we might get into troubles by doing make_ref() when
690 # things are not initialized yet. So in this case, simply use
691 # str2charp() and "leak" the string.
692 w_typename = space.getattr(w_type, space.wrap('__name__'))
693 heaptype = rffi.cast(PyHeapTypeObject, pto)
694 heaptype.c_ht_name = make_ref(space, w_typename)
695 from pypy.module.cpyext.bytesobject import PyString_AsString
696 pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name)
697 else:
698 pto.c_tp_name = rffi.str2charp(w_type.name)
699 # uninitialized fields:
700 # c_tp_print
701 # XXX implement
702 # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html )
703 w_base = best_base(space, w_type.bases_w)
704 pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
705
706 if builder.cpyext_type_init is not None:
707 builder.cpyext_type_init.append((pto, w_type))
708 else:
709 finish_type_1(space, pto)
710 finish_type_2(space, pto, w_type)
711
712 pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
713 if pto.c_tp_base:
714 if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
715 pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
716 if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize:
717 pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize
718
719 # will be filled later on with the correct value
720 # may not be 0
721 if space.is_w(w_type, space.w_object):
722 pto.c_tp_new = rffi.cast(newfunc, 1)
723 update_all_slots(space, w_type, pto)
724 pto.c_tp_flags |= Py_TPFLAGS_READY
725 return pto
726
727def py_type_ready(space, pto):
728 if pto.c_tp_flags & Py_TPFLAGS_READY:
729 return
730 type_realize(space, rffi.cast(PyObject, pto))
731
732@cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
733def PyType_Ready(space, pto):
734 py_type_ready(space, pto)
735 return 0
736
737def type_realize(space, py_obj):
738 pto = rffi.cast(PyTypeObjectPtr, py_obj)
739 assert pto.c_tp_flags & Py_TPFLAGS_READY == 0
740 assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
741 pto.c_tp_flags |= Py_TPFLAGS_READYING
742 try:
743 w_obj = _type_realize(space, py_obj)
744 finally:
745 name = rffi.charp2str(pto.c_tp_name)
746 pto.c_tp_flags &= ~Py_TPFLAGS_READYING
747 pto.c_tp_flags |= Py_TPFLAGS_READY
748 return w_obj
749
750def solid_base(space, w_type):
751 typedef = w_type.layout.typedef
752 return space.gettypeobject(typedef)
753
754def best_base(space, bases_w):
755 if not bases_w:
756 return None
757 return find_best_base(bases_w)
758
759def inherit_slots(space, pto, w_base):
760 # XXX missing: nearly everything
761 base_pyo = make_ref(space, w_base)
762 try:
763 base = rffi.cast(PyTypeObjectPtr, base_pyo)
764 if not pto.c_tp_dealloc:
765 pto.c_tp_dealloc = base.c_tp_dealloc
766 if not pto.c_tp_init:
767 pto.c_tp_init = base.c_tp_init
768 if not pto.c_tp_alloc:
769 pto.c_tp_alloc = base.c_tp_alloc
770 # XXX check for correct GC flags!
771 if not pto.c_tp_free:
772 pto.c_tp_free = base.c_tp_free
773 if not pto.c_tp_setattro:
774 pto.c_tp_setattro = base.c_tp_setattro
775 if not pto.c_tp_getattro:
776 pto.c_tp_getattro = base.c_tp_getattro
777 finally:
778 Py_DecRef(space, base_pyo)
779
780def _type_realize(space, py_obj):
781 """
782 Creates an interpreter type from a PyTypeObject structure.
783 """
784 # missing:
785 # unsupported:
786 # tp_mro, tp_subclasses
787 py_type = rffi.cast(PyTypeObjectPtr, py_obj)
788
789 if not py_type.c_tp_base:
790 # borrowed reference, but w_object is unlikely to disappear
791 base = as_pyobj(space, space.w_object)
792 py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
793
794 finish_type_1(space, py_type)
795
796 if py_type.c_ob_type:
797 w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
798 else:
799 # Somehow the tp_base type is created with no ob_type, notably
800 # PyString_Type and PyBaseString_Type
801 # While this is a hack, cpython does it as well.
802 w_metatype = space.w_type
803
804 w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
805 track_reference(space, py_obj, w_obj)
806 w_obj.__init__(space, py_type)
807 w_obj.ready()
808
809 finish_type_2(space, py_type, w_obj)
810 # inheriting tp_as_* slots
811 base = py_type.c_tp_base
812 if base:
813 if not py_type.c_tp_as_number: py_type.c_tp_as_number = base.c_tp_as_number
814 if not py_type.c_tp_as_sequence: py_type.c_tp_as_sequence = base.c_tp_as_sequence
815 if not py_type.c_tp_as_mapping: py_type.c_tp_as_mapping = base.c_tp_as_mapping
816 if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer
817
818 return w_obj
819
820def finish_type_1(space, pto):
821 """
822 Sets up tp_bases, necessary before creating the interpreter type.
823 """
824 base = pto.c_tp_base
825 base_pyo = rffi.cast(PyObject, pto.c_tp_base)
826 if base and not base.c_tp_flags & Py_TPFLAGS_READY:
827 name = rffi.charp2str(base.c_tp_name)
828 type_realize(space, base_pyo)
829 if base and not pto.c_ob_type: # will be filled later
830 pto.c_ob_type = base.c_ob_type
831 if not pto.c_tp_bases:
832 if not base:
833 bases = space.newtuple([])
834 else:
835 bases = space.newtuple([from_ref(space, base_pyo)])
836 pto.c_tp_bases = make_ref(space, bases)
837
838def finish_type_2(space, pto, w_obj):
839 """
840 Sets up other attributes, when the interpreter type has been created.
841 """
842 pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
843 base = pto.c_tp_base
844 if base:
845 inherit_special(space, pto, base)
846 for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
847 inherit_slots(space, pto, w_base)
848
849 if not pto.c_tp_setattro:
850 from pypy.module.cpyext.object import PyObject_GenericSetAttr
851 pto.c_tp_setattro = llhelper(
852 PyObject_GenericSetAttr.api_func.functype,
853 PyObject_GenericSetAttr.api_func.get_wrapper(space))
854
855 if not pto.c_tp_getattro:
856 from pypy.module.cpyext.object import PyObject_GenericGetAttr
857 pto.c_tp_getattro = llhelper(
858 PyObject_GenericGetAttr.api_func.functype,
859 PyObject_GenericGetAttr.api_func.get_wrapper(space))
860
861 if w_obj.is_cpytype():
862 Py_DecRef(space, pto.c_tp_dict)
863 w_dict = w_obj.getdict(space)
864 pto.c_tp_dict = make_ref(space, w_dict)
865
866@cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
867def PyType_IsSubtype(space, a, b):
868 """Return true if a is a subtype of b.
869 """
870 w_type1 = from_ref(space, rffi.cast(PyObject, a))
871 w_type2 = from_ref(space, rffi.cast(PyObject, b))
872 return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?
873
874@cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject, result_is_ll=True)
875def PyType_GenericAlloc(space, type, nitems):
876 from pypy.module.cpyext.object import _PyObject_NewVar
877 return _PyObject_NewVar(space, type, nitems)
878
879@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
880def PyType_GenericNew(space, type, w_args, w_kwds):
881 return generic_cpy_call(
882 space, type.c_tp_alloc, type, 0)
883
884@cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL,
885 result_borrowed=True)
886def _PyType_Lookup(space, type, w_name):
887 """Internal API to look for a name through the MRO.
888 This returns a borrowed reference, and doesn't set an exception!"""
889 w_type = from_ref(space, rffi.cast(PyObject, type))
890 assert isinstance(w_type, W_TypeObject)
891
892 if not space.isinstance_w(w_name, space.w_str):
893 return None
894 name = space.str_w(w_name)
895 w_obj = w_type.lookup(name)
896 # this assumes that w_obj is not dynamically created, but will stay alive
897 # until w_type is modified or dies. Assuming this, we return a borrowed ref
898 return w_obj
899
900@cpython_api([PyTypeObjectPtr], lltype.Void)
901def PyType_Modified(space, w_obj):
902 """Invalidate the internal lookup cache for the type and all of its
903 subtypes. This function must be called after any manual
904 modification of the attributes or base classes of the type.
905 """
906 # Invalidate the type cache in case of a builtin type.
907 if not isinstance(w_obj, W_TypeObject):
908 return
909 if w_obj.is_cpytype():
910 w_obj.mutated(None)
911