Commit 8e2b41a2 authored by Thomas Heller's avatar Thomas Heller

Upgrade to ctypes version 0.9.9.7.

Summary of changes:

- support for 'variable sized' data
- support for anonymous structure/union fields
- fix severe bug with certain arrays or structures containing more than 256 fields
parent 1e06746b
......@@ -342,6 +342,14 @@ static PyMethodDef CDataType_methods[] = {
static PyObject *
CDataType_repeat(PyObject *self, Py_ssize_t length)
{
if (length < 0)
return PyErr_Format(PyExc_ValueError,
#if (PY_VERSION_HEX < 0x02050000)
"Array length must be >= 0, not %d",
#else
"Array length must be >= 0, not %zd",
#endif
length);
return CreateArrayType(self, length);
}
......@@ -1809,23 +1817,62 @@ GetKeepedObjects(CDataObject *target)
}
static PyObject *
unique_key(CDataObject *target, int index)
unique_key(CDataObject *target, Py_ssize_t index)
{
char string[256]; /* XXX is that enough? */
char string[256];
char *cp = string;
*cp++ = index + '0';
size_t bytes_left;
assert(sizeof(string) - 1 > sizeof(Py_ssize_t) * 2);
#if (PY_VERSION_HEX < 0x02050000)
cp += sprintf(cp, "%x", index);
#else
#ifdef MS_WIN32
/* MSVC does not understand the 'z' size specifier */
cp += sprintf(cp, "%Ix", index);
#else
cp += sprintf(cp, "%zx", index);
#endif
#endif
while (target->b_base) {
*cp++ = target->b_index + '0';
bytes_left = sizeof(string) - (cp - string) - 1;
/* Hex format needs 2 characters per byte */
if (bytes_left < sizeof(Py_ssize_t) * 2) {
PyErr_SetString(PyExc_ValueError,
"ctypes object structure too deep");
return NULL;
}
#if (PY_VERSION_HEX < 0x02050000)
cp += sprintf(cp, ":%x", (int)target->b_index);
#else
#ifdef MS_WIN32
cp += sprintf(cp, ":%Ix", (size_t)target->b_index);
#else
cp += sprintf(cp, ":%zx", (size_t)target->b_index);
#endif
#endif
target = target->b_base;
}
return PyString_FromStringAndSize(string, cp-string);
}
/* Keep a reference to 'keep' in the 'target', at index 'index' */
/*
* KeepRef travels the target's b_base pointer down to the root,
* building a sequence of indexes during the path. The indexes, which are a
* couple of small integers, are used to build a byte string usable as
* key int the root object's _objects dict.
* Keep a reference to 'keep' in the 'target', at index 'index'.
*
* If 'keep' is None, do nothing.
*
* Otherwise create a dictionary (if it does not yet exist) id the root
* objects 'b_objects' item, which will store the 'keep' object under a unique
* key.
*
* The unique_key helper travels the target's b_base pointer down to the root,
* building a string containing hex-formatted indexes found during traversal,
* separated by colons.
*
* The index tuple is used as a key into the root object's b_objects dict.
*
* Note: This function steals a refcount of the third argument, even if it
* fails!
*/
static int
KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep)
......@@ -1846,6 +1893,10 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep)
return 0;
}
key = unique_key(target, index);
if (key == NULL) {
Py_DECREF(keep);
return -1;
}
result = PyDict_SetItem(ob->b_objects, key, keep);
Py_DECREF(key);
Py_DECREF(keep);
......@@ -2611,11 +2662,11 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
*(void **)self->b_ptr = address;
Py_INCREF((PyObject *)dll); /* for KeepRef */
if (-1 == KeepRef((CDataObject *)self, 0, dll)) {
Py_DECREF((PyObject *)self);
return NULL;
}
Py_INCREF((PyObject *)dll); /* for KeepRef above */
Py_INCREF(self);
self->callable = (PyObject *)self;
......@@ -2751,11 +2802,11 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
correctly...
*/
Py_INCREF((PyObject *)self); /* for KeepRef */
if (-1 == KeepRef((CDataObject *)self, 0, (PyObject *)self)) {
Py_DECREF((PyObject *)self);
return NULL;
}
Py_INCREF((PyObject *)self); /* for KeepRef above */
return (PyObject *)self;
}
......@@ -3520,7 +3571,7 @@ Array_item(PyObject *_self, Py_ssize_t index)
int offset, size;
StgDictObject *stgdict;
if (index < 0 || index >= self->b_length) {
if (self->b_length == 0 || index < 0 || (self->b_length > 1 && index >= self->b_length)) {
PyErr_SetString(PyExc_IndexError,
"invalid index");
return NULL;
......@@ -3549,11 +3600,11 @@ Array_slice(PyObject *_self, Py_ssize_t ilow, Py_ssize_t ihigh)
if (ilow < 0)
ilow = 0;
else if (ilow > self->b_length)
else if (ilow > self->b_length && self->b_length != 1)
ilow = self->b_length;
if (ihigh < ilow)
ihigh = ilow;
else if (ihigh > self->b_length)
else if (ihigh > self->b_length && self->b_length != 1)
ihigh = self->b_length;
len = ihigh - ilow;
......@@ -3596,7 +3647,8 @@ Array_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value)
}
stgdict = PyObject_stgdict((PyObject *)self);
if (index < 0 || index >= stgdict->length) {
if (self->b_length == 0 || index < 0
|| (self->b_length > 1 && index >= self->b_length)) {
PyErr_SetString(PyExc_IndexError,
"invalid index");
return -1;
......@@ -3623,17 +3675,19 @@ Array_ass_slice(PyObject *_self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *va
if (ilow < 0)
ilow = 0;
else if (ilow > self->b_length)
else if (ilow > self->b_length && self->b_length != 1)
ilow = self->b_length;
if (ihigh < 0)
ihigh = 0;
if (ihigh < ilow)
ihigh = ilow;
else if (ihigh > self->b_length)
else if (ihigh > self->b_length && self->b_length != 1)
ihigh = self->b_length;
len = PySequence_Length(value);
if (len != ihigh - ilow) {
if (self->b_length != 1 && len != ihigh - ilow) {
PyErr_SetString(PyExc_ValueError,
"Can only assign sequence of same size");
return -1;
......@@ -4020,7 +4074,8 @@ static PyObject *
Pointer_item(PyObject *_self, Py_ssize_t index)
{
CDataObject *self = (CDataObject *)_self;
int size, offset;
int size;
Py_ssize_t offset;
StgDictObject *stgdict, *itemdict;
PyObject *proto;
......@@ -4030,9 +4085,9 @@ Pointer_item(PyObject *_self, Py_ssize_t index)
return NULL;
}
stgdict = PyObject_stgdict((PyObject *)self);
assert(stgdict);
assert(stgdict->proto);
proto = stgdict->proto;
/* XXXXXX MAKE SURE PROTO IS NOT NULL! */
......@@ -4040,7 +4095,7 @@ Pointer_item(PyObject *_self, Py_ssize_t index)
size = itemdict->size;
offset = index * itemdict->size;
return CData_get(stgdict->proto, stgdict->getfunc, (PyObject *)self,
return CData_get(proto, stgdict->getfunc, (PyObject *)self,
index, size, (*(char **)self->b_ptr) + offset);
}
......@@ -4049,7 +4104,9 @@ Pointer_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value)
{
CDataObject *self = (CDataObject *)_self;
int size;
StgDictObject *stgdict;
Py_ssize_t offset;
StgDictObject *stgdict, *itemdict;
PyObject *proto;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
......@@ -4064,16 +4121,17 @@ Pointer_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value)
}
stgdict = PyObject_stgdict((PyObject *)self);
if (index != 0) {
PyErr_SetString(PyExc_IndexError,
"invalid index");
return -1;
}
size = stgdict->size / stgdict->length;
assert(stgdict);
assert(stgdict->proto);
/* XXXXX Make sure proto is NOT NULL! */
return CData_set((PyObject *)self, stgdict->proto, stgdict->setfunc, value,
index, size, *(void **)self->b_ptr);
proto = stgdict->proto;
/* XXXXXX MAKE SURE PROTO IS NOT NULL! */
itemdict = PyType_stgdict(proto);
size = itemdict->size;
offset = index * itemdict->size;
return CData_set((PyObject *)self, proto, stgdict->setfunc, value,
index, size, (*(char **)self->b_ptr) + offset);
}
static PyObject *
......@@ -4090,8 +4148,8 @@ Pointer_get_contents(CDataObject *self, void *closure)
stgdict = PyObject_stgdict((PyObject *)self);
assert(stgdict);
return CData_FromBaseObj(stgdict->proto,
(PyObject *)self, 0,
*(void **)self->b_ptr);
(PyObject *)self, 0,
*(void **)self->b_ptr);
}
static int
......@@ -4439,7 +4497,7 @@ cast_check_pointertype(PyObject *arg)
}
static PyObject *
cast(void *ptr, PyObject *ctype)
cast(void *ptr, PyObject *src, PyObject *ctype)
{
CDataObject *result;
if (0 == cast_check_pointertype(ctype))
......@@ -4447,6 +4505,36 @@ cast(void *ptr, PyObject *ctype)
result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
if (result == NULL)
return NULL;
/*
The casted objects '_objects' member:
It must certainly contain the source objects one.
It must contain the source object itself.
*/
if (CDataObject_Check(src)) {
CDataObject *obj = (CDataObject *)src;
/* CData_GetContainer will initialize src.b_objects, we need
this so it can be shared */
CData_GetContainer(obj);
/* But we need a dictionary! */
if (obj->b_objects == Py_None) {
Py_DECREF(Py_None);
obj->b_objects = PyDict_New();
}
Py_INCREF(obj->b_objects);
result->b_objects = obj->b_objects;
if (result->b_objects) {
PyObject *index = PyLong_FromVoidPtr((void *)src);
int rc;
if (index == NULL)
return NULL;
rc = PyDict_SetItem(result->b_objects, index, src);
Py_DECREF(index);
if (rc == -1)
return NULL;
}
}
/* Should we assert that result is a pointer type? */
memcpy(result->b_ptr, &ptr, sizeof(void *));
return (PyObject *)result;
......@@ -4581,7 +4669,7 @@ init_ctypes(void)
#endif
PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL));
PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI));
PyModule_AddStringConstant(m, "__version__", "0.9.9.6");
PyModule_AddStringConstant(m, "__version__", "0.9.9.7");
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
......
......@@ -1444,7 +1444,64 @@ set_conversion_mode(PyObject *self, PyObject *args)
}
#endif
static PyObject *
resize(PyObject *self, PyObject *args)
{
CDataObject *obj;
StgDictObject *dict;
Py_ssize_t size;
if (!PyArg_ParseTuple(args,
#if (PY_VERSION_HEX < 0x02050000)
"Oi:resize",
#else
"On:resize",
#endif
(PyObject *)&obj, &size))
return NULL;
dict = PyObject_stgdict((PyObject *)obj);
if (dict == NULL) {
PyErr_SetString(PyExc_TypeError,
"excepted ctypes instance");
return NULL;
}
if (size < dict->size) {
PyErr_Format(PyExc_ValueError,
"minimum size is %d", dict->size);
return NULL;
}
if (obj->b_needsfree == 0) {
PyErr_Format(PyExc_ValueError,
"Memory cannot be resized because this object doesn't own it");
return NULL;
}
if (size <= sizeof(obj->b_value)) {
/* internal default buffer is large enough */
obj->b_size = size;
goto done;
}
if (obj->b_size <= sizeof(obj->b_value)) {
/* We are currently using the objects default buffer, but it
isn't large enough any more. */
void *ptr = PyMem_Malloc(size);
if (ptr == NULL)
return PyErr_NoMemory();
memset(ptr, 0, size);
memmove(ptr, obj->b_ptr, obj->b_size);
obj->b_ptr = ptr;
obj->b_size = size;
} else {
obj->b_ptr = PyMem_Realloc(obj->b_ptr, size);
obj->b_size = size;
}
done:
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef module_methods[] = {
{"resize", resize, METH_VARARGS, "Resize the memory buffer of a ctypes instance"},
#ifdef CTYPES_UNICODE
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
#endif
......
......@@ -59,7 +59,7 @@ struct tagCDataObject {
Py_ssize_t b_length; /* number of references we need */
Py_ssize_t b_index; /* index of this object into base's
b_object list */
PyObject *b_objects; /* list of references we need to keep */
PyObject *b_objects; /* dictionary of references we need to keep, or Py_None */
union value b_value;
};
......@@ -181,6 +181,7 @@ typedef struct {
PyObject *proto; /* a type or NULL */
GETFUNC getfunc; /* getter function if proto is NULL */
SETFUNC setfunc; /* setter function if proto is NULL */
int anonymous;
} CFieldObject;
/* A subclass of PyDictObject, used as the instance dictionary of ctypes
......
......@@ -193,3 +193,198 @@ epilogue:
#endif /* ifndef __x86_64__ */
#endif /* defined __i386__ */
#ifdef __i386__
/* -----------------------------------------------------------------------
darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003 Red Hat, Inc.
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
/*
* This file is based on sysv.S and then hacked up by Ronald who hasn't done
* assembly programming in 8 years.
*/
#ifndef __x86_64__
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.text
.globl _ffi_prep_args
.align 4
.globl _ffi_call_SYSV
_ffi_call_SYSV:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
/* Make room for all of the new args. */
movl 16(%ebp),%ecx
subl %ecx,%esp
movl %esp,%eax
/* Place all of the ffi_prep_args in position */
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
/* Return stack to previous state and call the function */
addl $8,%esp
call *28(%ebp)
/* Remove the space we pushed for the args */
movl 16(%ebp),%ecx
addl %ecx,%esp
/* Load %ecx with the return type code */
movl 20(%ebp),%ecx
/* If the return value pointer is NULL, assume no return value. */
cmpl $0,24(%ebp)
jne retint
/* Even if there is no space for the return value, we are
obliged to handle floating-point values. */
cmpl $FFI_TYPE_FLOAT,%ecx
jne noretval
fstp %st(0)
jmp epilogue
retint:
cmpl $FFI_TYPE_INT,%ecx
jne retfloat
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
jmp epilogue
retfloat:
cmpl $FFI_TYPE_FLOAT,%ecx
jne retdouble
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
fstps (%ecx)
jmp epilogue
retdouble:
cmpl $FFI_TYPE_DOUBLE,%ecx
jne retlongdouble
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
fstpl (%ecx)
jmp epilogue
retlongdouble:
cmpl $FFI_TYPE_LONGDOUBLE,%ecx
jne retint64
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
fstpt (%ecx)
jmp epilogue
retint64:
cmpl $FFI_TYPE_SINT64,%ecx
jne retstruct
/* Load %ecx with the pointer to storage for the return value */
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
retstruct:
/* Nothing to do! */
noretval:
epilogue:
movl %ebp,%esp
popl %ebp
ret
.LFE1:
.ffi_call_SYSV_end:
#if 0
.size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
#endif
#if 0
.section .eh_frame,EH_FRAME_FLAGS,@progbits
.Lframe1:
.long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.long 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#ifdef __PIC__
.ascii "zR\0" /* CIE Augmentation */
#else
.ascii "\0" /* CIE Augmentation */
#endif
.byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
.byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
.byte 0x8 /* CIE RA Column */
#ifdef __PIC__
.byte 0x1 /* .uleb128 0x1; Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.byte 0x4 /* .uleb128 0x4 */
.byte 0x4 /* .uleb128 0x4 */
.byte 0x88 /* DW_CFA_offset, column 0x8 */
.byte 0x1 /* .uleb128 0x1 */
.align 4
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
#ifdef __PIC__
.long .LFB1-. /* FDE initial location */
#else
.long .LFB1 /* FDE initial location */
#endif
.long .LFE1-.LFB1 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI0-.LFB1
.byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI1-.LCFI0
.byte 0xd /* DW_CFA_def_cfa_register */
.byte 0x5 /* .uleb128 0x5 */
.align 4
.LEFDE1:
#endif
#endif /* ifndef __x86_64__ */
#endif /* defined __i386__ */
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.text
.globl ffi_prep_args
# This assumes we are using gas.
.balign 16
.globl _ffi_call_SYSV
_ffi_call_SYSV:
pushl %ebp
movl %esp,%ebp
# Make room for all of the new args.
movl 16(%ebp),%ecx
subl %ecx,%esp
movl %esp,%eax
# Place all of the ffi_prep_args in position
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
# Return stack to previous state and call the function
addl $8,%esp
# FIXME: Align the stack to a 128-bit boundary to avoid
# potential performance hits.
call *28(%ebp)
# Remove the space we pushed for the args
movl 16(%ebp),%ecx
addl %ecx,%esp
# Load %ecx with the return type code
movl 20(%ebp),%ecx
# If the return value pointer is NULL, assume no return value.
cmpl $0,24(%ebp)
jne retint
# Even if there is no space for the return value, we are
# obliged to handle floating-point values.
cmpl $2,%ecx # Float_type
jne noretval
fstp %st(0)
jmp epilogue
retint:
cmpl $1,%ecx # Int_type
jne retfloat
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
jmp epilogue
retfloat:
cmpl $2,%ecx # Float_type
jne retdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstps (%ecx)
jmp epilogue
retdouble:
cmpl $3,%ecx # Double_type
jne retlongdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpl (%ecx)
jmp epilogue
retlongdouble:
cmpl $4,%ecx # Longdouble_type
jne retint64
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpt (%ecx)
jmp epilogue
retint64:
cmpl $12,%ecx # SINT64_type
jne retstruct
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
retstruct:
# Nothing to do!
noretval:
epilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_SYSV_end:
# This assumes we are using gas.
.balign 16
.globl _ffi_call_STDCALL
_ffi_call_STDCALL:
pushl %ebp
movl %esp,%ebp
# Make room for all of the new args.
movl 16(%ebp),%ecx
subl %ecx,%esp
movl %esp,%eax
# Place all of the ffi_prep_args in position
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
# Return stack to previous state and call the function
addl $8,%esp
# FIXME: Align the stack to a 128-bit boundary to avoid
# potential performance hits.
call *28(%ebp)
# stdcall functions pop arguments off the stack themselves
# Load %ecx with the return type code
movl 20(%ebp),%ecx
# If the return value pointer is NULL, assume no return value.
cmpl $0,24(%ebp)
jne sc_retint
# Even if there is no space for the return value, we are
# obliged to handle floating-point values.
cmpl $2,%ecx # Float_type
jne sc_noretval
fstp %st(0)
jmp sc_epilogue
sc_retint:
cmpl $1,%ecx # Int_type
jne sc_retfloat
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
jmp sc_epilogue
sc_retfloat:
cmpl $2,%ecx # Float_type
jne sc_retdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstps (%ecx)
jmp sc_epilogue
sc_retdouble:
cmpl $2,%ecx # Double_type
jne sc_retlongdouble
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpl (%ecx)
jmp sc_epilogue
sc_retlongdouble:
cmpl $4,%ecx # Longdouble_type
jne sc_retint64
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
fstpt (%ecx)
jmp sc_epilogue
sc_retint64:
cmpl $12,%ecx # SINT64_Type
jne sc_retstruct
# Load %ecx with the pointer to storage for the return value
movl 24(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
sc_retstruct:
# Nothing to do!
sc_noretval:
sc_epilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_STDCALL_end:
......@@ -142,30 +142,129 @@ PyObject_stgdict(PyObject *self)
return PyType_stgdict((PyObject *)self->ob_type);
}
#if 0
/* work in progress: anonymous structure fields */
int
GetFields(PyObject *desc, int *pindex, int *psize, int *poffset, int *palign, int pack);
/* descr is the descriptor for a field marked as anonymous. Get all the
_fields_ descriptors from descr->proto, create new descriptors with offset
and index adjusted, and stuff them into type.
*/
static int
MakeFields(PyObject *type, CFieldObject *descr,
Py_ssize_t index, Py_ssize_t offset)
{
Py_ssize_t i;
PyObject *fields;
PyObject *fieldlist;
fields = PyObject_GetAttrString(descr->proto, "_fields_");
if (fields == NULL)
return -1;
fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence");
Py_DECREF(fields);
if (fieldlist == NULL)
return -1;
for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) {
PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */
PyObject *fname, *ftype;
CFieldObject *fdescr;
CFieldObject *new_descr;
// Convert to PyArg_UnpackTuple...
if (!PyArg_ParseTuple(pair, "OO", &fname, &ftype)) {
Py_DECREF(fieldlist);
return -1;
}
fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname);
if (fdescr == NULL) {
Py_DECREF(fieldlist);
return -1;
}
if (fdescr->ob_type != &CField_Type) {
PyErr_SetString(PyExc_TypeError, "unexpected type");
Py_DECREF(fdescr);
Py_DECREF(fieldlist);
return -1;
}
if (fdescr->anonymous) {
int rc = MakeFields(type, fdescr,
index + fdescr->index,
offset + fdescr->offset);
Py_DECREF(fdescr);
if (rc == -1) {
Py_DECREF(fieldlist);
return -1;
}
continue;
}
new_descr = (CFieldObject *)PyObject_CallObject((PyObject *)&CField_Type, NULL);
assert(new_descr->ob_type == &CField_Type);
if (new_descr == NULL) {
Py_DECREF(fdescr);
Py_DECREF(fieldlist);
return -1;
}
new_descr->size = fdescr->size;
new_descr->offset = fdescr->offset + offset;
new_descr->index = fdescr->index + index;
new_descr->proto = fdescr->proto;
Py_XINCREF(new_descr->proto);
new_descr->getfunc = fdescr->getfunc;
new_descr->setfunc = fdescr->setfunc;
Py_DECREF(fdescr);
if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) {
Py_DECREF(fieldlist);
Py_DECREF(new_descr);
return -1;
}
Py_DECREF(new_descr);
}
Py_DECREF(fieldlist);
return 0;
}
/* Iterate over the names in the type's _anonymous_ attribute, if present,
*/
static int
MakeAnonFields(PyObject *type)
{
int i;
PyObject *tuples = PyObject_GetAttrString(desc, "_fields_");
if (tuples == NULL)
PyObject *anon;
PyObject *anon_names;
Py_ssize_t i;
anon = PyObject_GetAttrString(type, "_anonymous_");
if (anon == NULL) {
PyErr_Clear();
return 0;
}
anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence");
Py_DECREF(anon);
if (anon_names == NULL)
return -1;
if (!PyTuple_Check(tuples))
return -1; /* leak */
for (i = 0; i < PyTuple_GET_SIZE(tuples); ++i) {
char *fname;
PyObject *dummy;
CFieldObject *field;
PyObject *pair = PyTuple_GET_ITEM(tuples, i);
if (!PyArg_ParseTuple(pair, "sO", &fname, &dummy))
return -1; /* leak */
field = PyObject_GetAttrString(desc, fname);
Py_DECREF(field);
for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) {
PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */
CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname);
if (descr == NULL) {
Py_DECREF(anon_names);
return -1;
}
assert(descr->ob_type == &CField_Type);
descr->anonymous = 1;
/* descr is in the field descriptor. */
if (-1 == MakeFields(type, (CFieldObject *)descr,
((CFieldObject *)descr)->index,
((CFieldObject *)descr)->offset)) {
Py_DECREF(descr);
Py_DECREF(anon_names);
return -1;
}
Py_DECREF(descr);
}
Py_DECREF(anon_names);
return 0;
}
#endif
/*
Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute,
......@@ -368,5 +467,5 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct)
stgdict->size = size;
stgdict->align = total_align;
stgdict->length = len; /* ADD ffi_ofs? */
return 0;
return MakeAnonFields(type);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment