def _PyString_Resize(space, ref, newsize): """A way to resize a string object even though it is "immutable". Only use this to build up a brand new string object; don't use this if the string may already be known in other parts of the code. It is an error to call this function if the refcount on the input string object is not one. Pass the address of an existing string object as an lvalue (it may be written into), and the new size desired. On success, *string holds the resized string object and 0 is returned; the address in *string may differ from its input value. If the reallocation fails, the original string object at *string is deallocated, *string is set to NULL, a memory exception is set, and -1 is returned. """ # XXX always create a new string so far py_str = rffi.cast(PyStringObject, ref[0]) if not py_str.c_buffer: raise OperationError(space.w_SystemError, space.wrap( "_PyString_Resize called on already created string")) try: py_newstr = new_empty_str(space, newsize) except MemoryError: Py_DecRef(space, ref[0]) ref[0] = lltype.nullptr(PyObject.TO) raise to_cp = newsize oldsize = py_str.c_size if oldsize < newsize: to_cp = oldsize for i in range(to_cp): py_newstr.c_buffer[i] = py_str.c_buffer[i] Py_DecRef(space, ref[0]) ref[0] = rffi.cast(PyObject, py_newstr) return 0
def frame_dealloc(space, py_obj): py_frame = rffi.cast(PyFrameObject, py_obj) py_code = rffi.cast(PyObject, py_frame.c_f_code) Py_DecRef(space, py_code) Py_DecRef(space, py_frame.c_f_globals) from pypy.module.cpyext.object import PyObject_dealloc PyObject_dealloc(space, py_obj)
def PyErr_SetExcInfo(space, w_type, w_value, w_traceback): """---Cython extension--- Set the exception info, as known from ``sys.exc_info()``. This refers to an exception that was already caught, not to an exception that was freshly raised. This function steals the references of the arguments. To clear the exception state, pass *NULL* for all three arguments. For general rules about the three arguments, see :c:func:`PyErr_Restore`. .. note:: This function is not normally used by code that wants to handle exceptions. Rather, it can be used when code needs to save and restore the exception state temporarily. Use :c:func:`PyErr_GetExcInfo` to read the exception state. """ if w_value is None or space.is_w(w_value, space.w_None): operror = None else: tb = None if w_traceback is not None: try: tb = pytraceback.check_traceback(space, w_traceback, '?') except OperationError: # catch and ignore bogus objects pass operror = OperationError(w_type, w_value, tb) # ec = space.getexecutioncontext() ec.set_sys_exc_info(operror) Py_DecRef(space, w_type) Py_DecRef(space, w_value) Py_DecRef(space, w_traceback)
def slice_dealloc(space, py_obj): """Frees allocated PyStringObject resources. """ py_slice = rffi.cast(PySliceObject, py_obj) Py_DecRef(space, py_slice.c_start) Py_DecRef(space, py_slice.c_stop) Py_DecRef(space, py_slice.c_step) from pypy.module.cpyext.object import PyObject_dealloc PyObject_dealloc(space, py_obj)
def PyErr_NormalizeException(space, exc_p, val_p, tb_p): """Under certain circumstances, the values returned by PyErr_Fetch() below can be "unnormalized", meaning that *exc is a class object but *val is not an instance of the same class. This function can be used to instantiate the class in that case. If the values are already normalized, nothing happens. The delayed normalization is implemented to improve performance.""" operr = OperationError(from_ref(space, exc_p[0]), from_ref(space, val_p[0])) operr.normalize_exception(space) Py_DecRef(space, exc_p[0]) Py_DecRef(space, val_p[0]) exc_p[0] = make_ref(space, operr.w_type) val_p[0] = make_ref(space, operr.get_w_value(space))
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) 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)) 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)) if w_obj.is_cpytype(): Py_DecRef(space, pto.c_tp_dict) w_dict = w_obj.getdict(space) pto.c_tp_dict = make_ref(space, w_dict)
def _PyTuple_Resize(space, ref, newsize): """Can be used to resize a tuple. newsize will be the new length of the tuple. Because tuples are supposed to be immutable, this should only be used if there is only one reference to the object. Do not use this if the tuple may already be known to some other part of the code. The tuple will always grow or shrink at the end. Think of this as destroying the old tuple and creating a new one, only more efficiently. Returns 0 on success. Client code should never assume that the resulting value of *p will be the same as before calling this function. If the object referenced by *p is replaced, the original *p is destroyed. On failure, returns -1 and sets *p to NULL, and raises MemoryError or SystemError.""" py_tuple = from_ref(space, ref[0]) if not PyTuple_Check(space, py_tuple): PyErr_BadInternalCall(space) py_newtuple = PyTuple_New(space, newsize) to_cp = newsize oldsize = space.int_w(space.len(py_tuple)) if oldsize < newsize: to_cp = oldsize for i in range(to_cp): _setitem_tuple(py_newtuple, i, space.getitem(py_tuple, space.wrap(i))) Py_DecRef(space, ref[0]) ref[0] = make_ref(space, py_newtuple) return 0
def PyTuple_SetItem(space, w_t, pos, w_obj): if not PyTuple_Check(space, w_t): # XXX this should also steal a reference, test it!!! PyErr_BadInternalCall(space) _setitem_tuple(w_t, pos, w_obj) Py_DecRef(space, w_obj) # SetItem steals a reference! return 0
def PyObject_AsCharBuffer(space, obj, bufferp, sizep): """Returns a pointer to a read-only memory location usable as character-based input. The obj argument must support the single-segment character buffer interface. On success, returns 0, sets buffer to the memory location and size to the buffer length. Returns -1 and sets a TypeError on error. """ pto = obj.c_ob_type pb = pto.c_tp_as_buffer if not (pb and pb.c_bf_getbuffer): raise OperationError( space.w_TypeError, space.wrap("expected an object with the buffer interface")) with lltype.scoped_alloc(Py_buffer) as view: ret = generic_cpy_call(space, pb.c_bf_getbuffer, obj, view, rffi.cast(rffi.INT_real, PyBUF_SIMPLE)) if rffi.cast(lltype.Signed, ret) == -1: return -1 bufferp[0] = rffi.cast(rffi.CCHARP, view.c_buf) sizep[0] = view.c_len if pb.c_bf_releasebuffer: generic_cpy_call(space, pb.c_bf_releasebuffer, obj, view) Py_DecRef(space, view.c_obj) return 0
def type_alloc(space, w_metatype, itemsize=0): 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, flavor='raw', zero=True, add_memory_pressure=True) pto = heaptype.c_ht_type pto.c_ob_refcnt = 1 pto.c_ob_pypy_link = 0 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 pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 return rffi.cast(PyObject, heaptype)
def _type_realize(space, py_obj): """ Creates an interpreter type from a PyTypeObject structure. """ # missing: # inheriting tp_as_* slots # unsupported: # tp_mro, tp_subclasses py_type = rffi.cast(PyTypeObjectPtr, py_obj) if not py_type.c_tp_base: # borrowed reference, but w_object is unlikely to disappear base = make_ref(space, space.w_object) Py_DecRef(space, base) py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base) finish_type_1(space, py_type) w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type)) w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype) track_reference(space, py_obj, w_obj) w_obj.__init__(space, py_type) w_obj.ready() finish_type_2(space, py_type, w_obj) state = space.fromcache(RefcountState) state.non_heaptypes_w.append(w_obj) return w_obj
def PyString_ConcatAndDel(space, ref, newpart): """Create a new string object in *string containing the contents of newpart appended to string. This version decrements the reference count of newpart.""" try: PyString_Concat(space, ref, newpart) finally: Py_DecRef(space, newpart)
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, w_obj, base) for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)): if isinstance(w_base, W_TypeObject): inherit_slots(space, pto, w_base) #else: # w_base is a W_ClassObject, ignore it if not pto.c_tp_setattro: from pypy.module.cpyext.object import PyObject_GenericSetAttr pto.c_tp_setattro = llslot(space, PyObject_GenericSetAttr) if not pto.c_tp_getattro: from pypy.module.cpyext.object import PyObject_GenericGetAttr pto.c_tp_getattro = llslot(space, PyObject_GenericGetAttr) if w_obj.is_cpytype(): Py_DecRef(space, pto.c_tp_dict) w_dict = w_obj.getdict(space) # pass in the w_obj to convert any values that are # unbound GetSetProperty into bound PyGetSetDescrObject pto.c_tp_dict = make_ref(space, w_dict, w_obj)
def buffer_dealloc(space, py_obj): py_buf = rffi.cast(PyBufferObject, py_obj) if py_buf.c_b_base: Py_DecRef(space, py_buf.c_b_base) else: rffi.free_charp(rffi.cast(rffi.CCHARP, py_buf.c_b_ptr)) from pypy.module.cpyext.object import _dealloc _dealloc(space, py_obj)
def wrap_result(self, space, lresult): space.getbuiltinmodule("cpyext") from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, Py_DecRef result = rffi.cast(PyObject, lresult) w_obj = from_ref(space, result) if result: Py_DecRef(space, result) return w_obj
def unicode_dealloc(space, py_obj): py_unicode = rffi.cast(PyUnicodeObject, py_obj) Py_DecRef(space, py_unicode.c_defenc) if py_unicode.c_str: lltype.free(py_unicode.c_str, flavor="raw") from pypy.module.cpyext.object import _dealloc _dealloc(space, py_obj)
def test_coerce(self, space): w_obj1 = space.wrap(123) w_obj2 = space.wrap(456.789) pp1 = lltype.malloc(PyObjectP.TO, 1, flavor='raw') pp1[0] = make_ref(space, w_obj1) pp2 = lltype.malloc(PyObjectP.TO, 1, flavor='raw') pp2[0] = make_ref(space, w_obj2) assert PyNumber_Coerce(space, pp1, pp2) == 0 assert space.str_w(space.repr(from_ref(space, pp1[0]))) == '123.0' assert space.str_w(space.repr(from_ref(space, pp2[0]))) == '456.789' Py_DecRef(space, pp1[0]) Py_DecRef(space, pp2[0]) lltype.free(pp1, flavor='raw') # Yes, decrement twice since we decoupled between w_obj* and pp*[0]. Py_DecRef(space, w_obj1) Py_DecRef(space, w_obj2) lltype.free(pp2, flavor='raw')
def PyBuffer_Release(space, view): """ Releases a Py_buffer obtained from getbuffer ParseTuple's s*. This is not a complete re-implementation of the CPython API; it only provides a subset of CPython's behavior. """ Py_DecRef(space, view.c_obj)
def inherit_special(space, pto, base_pto): # XXX missing: copy basicsize and flags in a magical way flags = rffi.cast(lltype.Signed, pto.c_tp_flags) base_object_pyo = make_ref(space, space.w_object) base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo) if base_pto != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE: if not pto.c_tp_new: pto.c_tp_new = base_pto.c_tp_new Py_DecRef(space, base_object_pyo)
def _dealloc(space, obj): # This frees an object after its refcount dropped to zero, so we # assert that it is really zero here. assert obj.c_ob_refcnt == 0 pto = obj.c_ob_type obj_voidp = rffi.cast(rffi.VOIDP, obj) generic_cpy_call(space, pto.c_tp_free, obj_voidp) if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE: Py_DecRef(space, rffi.cast(PyObject, pto))
def member_setter(self, space, w_self, w_value): assert isinstance(self, W_MemberDescr) check_descr(space, w_self, self.w_type) pyref = make_ref(space, w_self) try: PyMember_SetOne( space, rffi.cast(rffi.CCHARP, pyref), self.member, w_value) finally: Py_DecRef(space, pyref)
def PyException_SetCause(space, w_exc, cause): """Set the cause associated with the exception to cause. Use NULL to clear it. There is no type check to make sure that cause is an exception instance. This steals a reference to cause.""" if cause: w_cause = from_ref(space, cause) Py_DecRef(space, cause) else: w_cause = space.w_None space.setattr(w_exc, space.wrap('__cause__'), w_cause)
def PyException_SetContext(space, w_exc, ctx): """Set the context associated with the exception to ctx. Use NULL to clear it. There is no type check to make sure that ctx is an exception instance. This steals a reference to ctx.""" if ctx: w_ctx = from_ref(space, ctx) Py_DecRef(space, ctx) else: w_ctx = space.w_None space.setattr(w_exc, space.wrap('__context__'), w_ctx)
def PyThreadState_Clear(space, tstate): """Reset all information in a thread state object. The global interpreter lock must be held.""" if not space.config.translation.thread: raise NoThreads Py_DecRef(space, tstate.c_dict) tstate.c_dict = lltype.nullptr(PyObject.TO) space.threadlocals.leave_thread(space) space.getexecutioncontext().cleanup_cpyext_state() rthread.gc_thread_die()
def test_fromstring(self, space): s = rffi.str2charp(u'sp\x09m'.encode("utf-8")) w_res = PyUnicode_FromString(space, s) assert space.unwrap(w_res) == u'sp\x09m' res = PyUnicode_FromStringAndSize(space, s, 4) w_res = from_ref(space, res) Py_DecRef(space, res) assert space.unwrap(w_res) == u'sp\x09m' rffi.free_charp(s)
def str_getcharbuffer(space, w_str, segment, ref): from pypy.module.cpyext.stringobject import PyString_AsString if segment != 0: raise OperationError(space.w_SystemError, space.wrap ("accessing non-existent string segment")) 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)
def PyString_Concat(space, ref, w_newpart): """Create a new string object in *string containing the contents of newpart appended to string; the caller will own the new reference. The reference to the old value of string will be stolen. If the new string cannot be created, the old reference to string will still be discarded and the value of *string will be set to NULL; the appropriate exception will be set.""" if not ref[0]: return if w_newpart is None or not PyString_Check(space, ref[0]) or \ not PyString_Check(space, w_newpart): Py_DecRef(space, ref[0]) ref[0] = lltype.nullptr(PyObject.TO) return w_str = from_ref(space, ref[0]) w_newstr = space.add(w_str, w_newpart) Py_DecRef(space, ref[0]) ref[0] = make_ref(space, w_newstr)
def wrap_binaryfunc_r(space, w_self, w_args, func): func_binary = rffi.cast(binaryfunc, func) check_num_args(space, w_args, 1) args_w = space.fixedview(w_args) ref = make_ref(space, w_self) if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and not space.is_true(space.issubtype(space.type(args_w[0]), space.type(w_self)))): return space.w_NotImplemented Py_DecRef(space, ref) return generic_cpy_call(space, func_binary, args_w[0], w_self)
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)
def PyUnicode_Resize(space, ref, newsize): # XXX always create a new string so far py_uni = rffi.cast(PyUnicodeObject, ref[0]) if not py_uni.c_str: raise oefmt(space.w_SystemError, "PyUnicode_Resize called on already created string") try: py_newuni = new_empty_unicode(space, newsize) except MemoryError: Py_DecRef(space, ref[0]) ref[0] = lltype.nullptr(PyObject.TO) raise to_cp = newsize oldsize = py_uni.c_length if oldsize < newsize: to_cp = oldsize for i in range(to_cp): py_newuni.c_str[i] = py_uni.c_str[i] Py_DecRef(space, ref[0]) ref[0] = rffi.cast(PyObject, py_newuni) return 0