Commit 4516a118 authored by Xavier Thompson's avatar Xavier Thompson

Use a POD struct defining the memory layout of wrappers to access the underlying cyobject

parent 394ab718
......@@ -294,7 +294,7 @@ def NAME(self, ARGDECLS):
stats = []
if not cclass_bases.args:
# the memory layout for the underlying cyobject should always be the same
# -> maybe use a single common base cclass in the future
# and match the memory layout of CyPyObject.
underlying_cyobject = self.synthesize_underlying_cyobject_attribute(node)
stats.append(underlying_cyobject)
......@@ -344,7 +344,7 @@ def NAME(self, ARGDECLS):
underlying_name_declarator = Nodes.CNameDeclaratorNode(
node.pos,
name=underlying_name,
cname=Naming.cypclass_attr_cname
cname=Naming.cypclass_wrapper_underlying_attr
)
underlying_cyobject = Nodes.CVarDefNode(
......@@ -1023,18 +1023,9 @@ def generate_cyp_class_wrapper_definition(type, wrapper_entry, constructor_entry
# __new__ can be defined by user and return another type
is_new_return_type = not new_entry or new_entry.type.return_type == type
# initialise PyObject fields
# allocate and initialise PyObject fields
if is_new_return_type and type.wrapper_type:
objstruct_cname = type.wrapper_type.objstruct_cname
cclass_wrapper_base = type.wrapped_base_type().wrapper_type
code.putln("if(self) {")
code.putln("%s * wrapper = (%s *) ::operator new(sizeof *wrapper);" % (objstruct_cname, objstruct_cname))
code.putln("((%s *)wrapper)->%s = self;" % (cclass_wrapper_base.objstruct_cname, Naming.cypclass_attr_cname))
code.putln("PyObject * wrapper_as_py = (PyObject *) wrapper;")
code.putln("wrapper_as_py->ob_refcnt = 0;")
code.putln("wrapper_as_py->ob_type = %s;" % type.wrapper_type.typeptr_cname)
code.putln("self->cy_pyobject = wrapper_as_py;")
code.putln("}")
generate_cypclass_wrapper_allocation(code, type.wrapper_type)
if init_entry:
init_entry = PyrexTypes.best_match(wrapper_arg_types,
......@@ -1124,3 +1115,18 @@ def generate_cyp_class_wrapper_definition(type, wrapper_entry, constructor_entry
code.putln("return self;")
code.putln("}")
def generate_cypclass_wrapper_allocation(code, wrapper_type):
"""
Generate allocation and essential setup of the wrapper object.
The cname of the cyobject is assumed to be 'self'.
The cname 'wrapper' is assumed to be available.
"""
objstruct_cname = wrapper_type.objstruct_cname
code.putln("if (self) {")
code.putln("%s * wrapper = (%s *) ::operator new(sizeof *wrapper);" % (objstruct_cname, objstruct_cname))
code.putln("((PyObject *)wrapper)->ob_refcnt = 0;")
code.putln("((PyObject *)wrapper)->ob_type = %s;" % wrapper_type.typeptr_cname)
code.putln("((%s *)wrapper)->%s = self;" % (Naming.cypclass_wrapper_layout_type, Naming.cypclass_wrapper_underlying_attr))
code.putln("self->cy_pyobject = (PyObject *) wrapper;")
code.putln("}")
......@@ -1686,7 +1686,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# for cyp wrappers, just decrement the atomic counter of the underlying type
parent_type = scope.parent_type
if parent_type.is_cyp_wrapper:
underlying_attribute_name = Naming.cypclass_attr_cname
underlying_attribute_name = Naming.cypclass_wrapper_underlying_attr
self.generate_self_cast(scope, code)
code.putln(
"CyObject * p_nogil_cyobject = p->%s;"
......
......@@ -166,8 +166,12 @@ exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
api_name = pyrex_prefix + "capi__"
# c name for underlying cypclass attribute in cypclass wrappers
cypclass_attr_cname = "nogil_cyobject"
# cname for the type that defines the essential memory layout of a cypclass wrapper.
cypclass_wrapper_layout_type = "CyPyObject"
# cname for the underlying cypclass attribute in the memory layout of a cypclass wrapper.
cypclass_wrapper_underlying_attr = "nogil_cyobject"
# the h and api guards get changed to:
# __PYX_HAVE__FILENAME (for ascii filenames)
......
......@@ -4180,7 +4180,6 @@ class CypClassType(CppClassType):
# _mro [CppClassType] or None the Method Resolution Order of this cypclass according to Python
# support_wrapper boolean whether this cypclass will be wrapped
# wrapper_type PyExtensionType or None the type of the cclass wrapper
# _wrapped_base_type CypClassType or None the type of the oldest wrapped cypclass base
is_cyp_class = 1
to_py_function = None
......@@ -4195,20 +4194,6 @@ class CypClassType(CppClassType):
self.wrapper_type = None
self._wrapped_base_type = None
# return the oldest left-path superclass such that all intervening classes have a wrapper
def wrapped_base_type(self):
# if the result has already been computed, return it
if self._wrapped_base_type is not None:
return self._wrapped_base_type
# find the first wrapped base (if there is one) and take the same oldest superclass
for base_type in self.base_classes:
if base_type.is_cyp_class and base_type.support_wrapper:
self._wrapped_base_type = base_type.wrapped_base_type()
return self._wrapped_base_type
# if no wrapped base was found, this type is the oldest wrapped base
self._wrapped_base_type = self
return self
# iterate over the direct bases that support wrapping
def iter_wrapped_base_types(self):
for base_type in self.base_classes:
......@@ -4252,11 +4237,10 @@ class CypClassType(CppClassType):
def create_from_py_utility_code(self, env):
if not self.wrapper_type:
return False
wrapper_objstruct = self.wrapped_base_type().wrapper_type.objstruct_cname
underlying_type_name = self.cname
self.from_py_function = "__Pyx_PyObject_AsCyObject<%s, %s>" % (wrapper_objstruct, underlying_type_name)
self.from_py_function = "__Pyx_PyObject_AsCyObject<%s>" % underlying_type_name
return True
def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None):
extra_args = [self.wrapper_type.typeptr_cname if self.wrapper_type else None]
......@@ -4265,7 +4249,7 @@ class CypClassType(CppClassType):
return self._assign_from_py_code(
source_code, result_code, error_pos, code, from_py_function, error_condition, extra_args=extra_args)
def empty_declaration_code(self):
if self._empty_declaration is None:
self._empty_declaration = self.declaration_code('', deref=1)
......
......@@ -75,6 +75,19 @@
int CyObject_TRYWLOCK();
};
/*
* A POD type that has a compatible memory layout with any wrapper for a cypclass.
*
* Serves as a:
* - convenience type to cast a wrapper and access its underlying cyobject pointer.
* - reference for the memory layout that all cypclass wrappers must respect.
*/
struct CyPyObject {
PyObject_HEAD
CyObject * nogil_cyobject;
};
/* All this is made available by member injection inside the module scope */
struct ActhonResultInterface : public CyObject {
......@@ -200,10 +213,9 @@
* - return NULL
*
* template:
* - W: the type of the extension type wrapper
* - U: the type of the underlying cypclass
*/
template <typename W, typename U>
template <typename U>
static inline U* __Pyx_PyObject_AsCyObject(PyObject * ob, PyTypeObject * type) {
// the PyObject is not of the expected type
if (ob->ob_type != type) {
......@@ -211,7 +223,7 @@
return NULL;
}
W * wrapper = (W *)ob;
CyPyObject * wrapper = (CyPyObject *)ob;
U * underlying = dynamic_cast<U *>(wrapper->nogil_cyobject);
// no underlying cyobject: shouldn't happen, playing it safe for now
......
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