Skip to content

Commit 958cb03

Browse files
authored
Merge pull request #3 from jordanbriere/add_default_callingconvention
Added post-construction initialization support.
2 parents 121a496 + 98d9853 commit 958cb03

File tree

4 files changed

+106
-27
lines changed

4 files changed

+106
-27
lines changed

src/core/modules/memory/memory_function.cpp

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -154,26 +154,11 @@ CFunction::CFunction(unsigned long ulAddr, object oCallingConvention, object oAr
154154

155155
// A custom calling convention will be used...
156156
m_eCallingConvention = CONV_CUSTOM;
157-
158-
// Check if default_convention is defined.
159-
if (PyObject_HasAttrString(oCallingConvention.ptr(), "default_convention"))
160-
{
161-
// Extract default_convention and pass it to oCallingConvention.
162-
Convention_t eCallingConvention = extract<Convention_t>(oCallingConvention.attr("default_convention"));
163-
m_oCallingConvention = oCallingConvention(m_tArgs, m_eReturnType, 4, eCallingConvention);
164-
}
165-
else
166-
{
167-
m_oCallingConvention = oCallingConvention(m_tArgs, m_eReturnType);
168-
}
169-
157+
m_oCallingConvention = oCallingConvention(m_tArgs, m_eReturnType);
170158
m_pCallingConvention = extract<ICallingConvention*>(m_oCallingConvention);
171159

172160
// Reserve a Python reference for DynamicHooks.
173161
Py_INCREF(m_oCallingConvention.ptr());
174-
175-
// Initialize our wrapper so that Python overrides are properly resolved.
176-
detail::initialize_wrapper(m_oCallingConvention.ptr(), get_pointer((ICallingConventionWrapper *)m_pCallingConvention));
177162
}
178163

179164
// Step 4: Get the DynCall calling convention
@@ -196,8 +181,11 @@ CFunction::CFunction(unsigned long ulAddr, Convention_t eCallingConvention,
196181

197182
CFunction::~CFunction()
198183
{
184+
if (!m_pCallingConvention)
185+
return;
186+
199187
// If the convention isn't flagged as hooked, then we need to take care of it.
200-
if (m_pCallingConvention && !m_pCallingConvention->m_bHooked)
188+
if (!m_pCallingConvention->m_bHooked)
201189
{
202190
// If we don't have a Python instance, then we can safely delete it.
203191
if (m_oCallingConvention.is_none())
@@ -206,6 +194,10 @@ CFunction::~CFunction()
206194
else if (Py_REFCNT(m_oCallingConvention.ptr()) > 1)
207195
Py_DECREF(m_oCallingConvention.ptr());
208196
}
197+
// If we are using a built-in convention that is currently hooked, let's flag it as no longer hooked
198+
// so that we know we are not bound to a CFunction anymore and can be deleted.
199+
else if (m_eCallingConvention != CONV_CUSTOM && !dynamic_cast<ICallingConventionWrapper *>(m_pCallingConvention))
200+
m_pCallingConvention->m_bHooked = false;
209201

210202
m_pCallingConvention = NULL;
211203
}
@@ -439,17 +431,24 @@ void CFunction::DeleteHook()
439431

440432
g_mapCallbacks.erase(pHook);
441433

442-
// Flag the convention as no longer hooked and being taken care of by DynamicHooks.
443-
pHook->m_pCallingConvention->m_bHooked = false;
444-
445-
// Release the Python reference we reserved for DynamicHooks.
446434
ICallingConventionWrapper *pConv = dynamic_cast<ICallingConventionWrapper *>(pHook->m_pCallingConvention);
447435
if (pConv)
448436
{
449-
PyObject *pOwner = detail::wrapper_base_::owner(pConv);
450-
if (pOwner && Py_REFCNT(pOwner))
451-
Py_DECREF(pOwner);
437+
if (pConv->m_bHooked)
438+
{
439+
// Flag the convention as no longer hooked and being taken care of by DynamicHooks.
440+
pHook->m_pCallingConvention->m_bHooked = false;
441+
442+
// Release the Python reference we reserved for DynamicHooks.
443+
PyObject *pOwner = detail::wrapper_base_::owner(pConv);
444+
if (pOwner && Py_REFCNT(pOwner))
445+
Py_DECREF(pOwner);
446+
}
452447
}
448+
// If we are a built-in convention bound to a CHook instance but not flagged as hooked anymore, then that
449+
// means we are no longer bound to a CFunction instance and can be safely deleted.
450+
else if (!pHook->m_pCallingConvention->m_bHooked)
451+
delete pHook->m_pCallingConvention;
453452

454453
// Set the calling convention to NULL, because DynamicHooks will delete it otherwise.
455454
pHook->m_pCallingConvention = NULL;

src/core/modules/memory/memory_wrap.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,18 @@ void export_calling_convention(scope _memory)
839839
no_init)
840840

841841
.def("__init__",
842-
make_constructor(&ICallingConventionWrapper::__init__,
843-
default_call_policies(),
844-
(arg("arg_types"), arg("return_type"), arg("alignment")=4, arg("default_convention")=CONV_CUSTOM)
842+
make_constructor(
843+
&ICallingConventionWrapper::__init__,
844+
post_constructor_policies<
845+
initialize_wrapper_policies<boost::shared_ptr<ICallingConventionWrapper> >
846+
>(
847+
make_function(
848+
&ICallingConventionWrapper::Initialize,
849+
default_call_policies(),
850+
args("self", "arg_types", "return_type", "alignment", "default_convention")
851+
)
852+
),
853+
("arg_types", "return_type", arg("alignment")=4, arg("default_convention")=CONV_CUSTOM)
845854
),
846855
"Initialize the calling convention.\n"
847856
"\n"

src/core/modules/memory/memory_wrap.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,27 @@ class ICallingConventionWrapper: public ICallingConvention, public wrapper<ICall
9595
);
9696
}
9797

98+
void Initialize(object self, object oArgTypes, DataType_t returnType, int iAlignment, Convention_t eDefaultConv)
99+
{
100+
// If we didn't receive a default convention on construction, try to resolve one from the Python instance.
101+
if (!m_pDefaultCallingConvention)
102+
{
103+
try
104+
{
105+
m_pDefaultCallingConvention = MakeDynamicHooksConvention(
106+
extract<Convention_t>(self.attr("default_convention")), m_vecArgTypes, m_returnType, m_iAlignment
107+
);
108+
}
109+
catch (error_already_set &)
110+
{
111+
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
112+
throw_error_already_set();
113+
114+
PyErr_Clear();
115+
}
116+
}
117+
}
118+
98119
virtual std::list<Register_t> GetRegisters()
99120
{
100121
override get_registers = get_override("get_registers");

src/core/utilities/wrap_macros.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,54 @@ typedef return_value_policy<copy_const_reference> copy_const_reference_policy;
248248

249249
typedef return_value_policy<return_by_value> return_by_value_policy;
250250

251+
//---------------------------------------------------------------------------------
252+
// Call policies that initializes the wrapper hierarchy.
253+
//---------------------------------------------------------------------------------
254+
template<typename HeldType, typename BasePolicies = default_call_policies, int iSelf = -1>
255+
struct initialize_wrapper_policies : BasePolicies
256+
{
257+
template<typename ArgumentPackage>
258+
static PyObject *postcall(const ArgumentPackage &args, PyObject *pResult)
259+
{
260+
PyObject *pSelf = detail::get(boost::mpl::int_<iSelf>(), args);
261+
detail::initialize_wrapper(
262+
pSelf,
263+
get_pointer((HeldType)extract<HeldType>(pSelf))
264+
);
265+
266+
return BasePolicies::postcall(args, pResult);
267+
}
268+
};
269+
270+
//---------------------------------------------------------------------------------
271+
// Provides post-construction initialization support of the Python instances.
272+
//---------------------------------------------------------------------------------
273+
template<typename BasePolicies = default_call_policies, int iSelf = -1>
274+
struct post_constructor_policies : BasePolicies
275+
{
276+
public:
277+
post_constructor_policies(object initializer):
278+
m_initializer(initializer)
279+
{
280+
}
281+
282+
template<typename ArgumentPackage>
283+
PyObject *postcall(const ArgumentPackage &args, PyObject *pResult)
284+
{
285+
BasePolicies::postcall(args, pResult);
286+
m_initializer(
287+
*(make_tuple(
288+
object(handle<>(incref(detail::get(boost::mpl::int_<iSelf>(), args))))) +
289+
boost::python::tuple(handle<>(args.base))
290+
)
291+
);
292+
293+
decref(pResult);
294+
return incref(Py_None); // __init__ should always return None
295+
}
296+
297+
private:
298+
object m_initializer;
299+
};
300+
251301
#endif // _WRAP_MACROS_H

0 commit comments

Comments
 (0)