Skip to content

Commit b61efd2

Browse files
committed
Solve bugs in python callbacks, improve python function generation.
1 parent faf397b commit b61efd2

File tree

2 files changed

+28
-43
lines changed

2 files changed

+28
-43
lines changed

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@
3333

3434
#include <Python.h>
3535

36-
#define PY_LOADER_IMPL_FUNCTION_TYPE_INVOKE_MOD "____metacall_py_loader_impl_function_type_invoke_module____"
37-
#define PY_LOADER_IMPL_FUNCTION_TYPE_INVOKE_FUNC "py_loader_impl_function_type_invoke"
36+
#define PY_LOADER_IMPL_FUNCTION_TYPE_INVOKE_FUNC "__py_loader_impl_function_type_invoke__"
3837

3938
typedef struct loader_impl_py_function_type
4039
{
@@ -73,9 +72,6 @@ typedef struct loader_impl_py_type
7372
PyObject * gc_debug_stats;
7473
#endif
7574

76-
PyObject * function_type_invoke_mod;
77-
PyObject * function_type_invoke_func;
78-
7975
} * loader_impl_py;
8076

8177
typedef struct loader_impl_py_function_type_invoke_state_type
@@ -115,19 +111,6 @@ static PyMethodDef py_loader_impl_function_type_invoke_defs[] =
115111
{ NULL, NULL, 0, NULL }
116112
};
117113

118-
static struct PyModuleDef py_loader_impl_function_type_invoke_module =
119-
{
120-
PyModuleDef_HEAD_INIT,
121-
PY_LOADER_IMPL_FUNCTION_TYPE_INVOKE_MOD,
122-
PyDoc_STR("Module for providing support for functions as values in the MetaCall type system."),
123-
sizeof(struct loader_impl_py_function_type_invoke_state_type),
124-
py_loader_impl_function_type_invoke_defs,
125-
NULL,
126-
NULL,
127-
NULL,
128-
NULL
129-
};
130-
131114
static void * py_loader_impl_value_ownership = NULL;
132115

133116
void py_loader_impl_value_owner_finalize(value v, void * owner)
@@ -464,13 +447,17 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
464447
/* Check if we are passing our own hook to the callback */
465448
if (PyCFunction_Check(obj) && PyCFunction_GET_FUNCTION(obj) == py_loader_impl_function_type_invoke)
466449
{
467-
loader_impl_py py_impl = loader_impl_get(impl);
450+
PyObject * invoke_state_capsule = PyCFunction_GET_SELF(obj);
468451

469-
loader_impl_py_function_type_invoke_state invoke_state;
452+
loader_impl_py_function_type_invoke_state invoke_state = PyCapsule_GetPointer(invoke_state_capsule, NULL);
470453

471-
invoke_state = (loader_impl_py_function_type_invoke_state)PyModule_GetState(py_impl->function_type_invoke_mod);
454+
function callback = invoke_state->callback;
472455

473-
return value_create_function(invoke_state->callback);
456+
Py_DECREF(invoke_state_capsule);
457+
458+
free(invoke_state);
459+
460+
return value_create_function(callback);
474461
}
475462

476463
discover_args_count = py_loader_impl_discover_func_args_count(obj);
@@ -527,7 +514,7 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
527514
/* Set up finalizer in order to free the value */
528515
value_finalizer(v, &py_loader_impl_value_owner_finalize);
529516

530-
log_write("metacall", LOG_LEVEL_WARNING, "Unrecognized python type");
517+
log_write("metacall", LOG_LEVEL_WARNING, "Unrecognized Python Type: %s", Py_TYPE(obj)->tp_name);
531518
}
532519

533520
return v;
@@ -645,13 +632,23 @@ PyObject * py_loader_impl_value_to_capi(loader_impl impl, loader_impl_py py_impl
645632
}
646633
else if (id == TYPE_FUNCTION)
647634
{
648-
loader_impl_py_function_type_invoke_state invoke_state;
635+
loader_impl_py_function_type_invoke_state invoke_state = malloc(sizeof(struct loader_impl_py_function_type_invoke_state_type));
636+
PyObject * invoke_state_capsule;
649637

650-
invoke_state = (loader_impl_py_function_type_invoke_state)PyModule_GetState(py_impl->function_type_invoke_mod);
638+
if (invoke_state == NULL)
639+
{
640+
return NULL;
641+
}
651642

643+
invoke_state->impl = impl;
644+
invoke_state->py_impl = py_impl;
652645
invoke_state->callback = value_to_function(v);
653646

654-
return py_impl->function_type_invoke_func;
647+
invoke_state_capsule = PyCapsule_New(invoke_state, NULL, NULL);
648+
649+
Py_INCREF(invoke_state_capsule);
650+
651+
return PyCFunction_New(py_loader_impl_function_type_invoke_defs, invoke_state_capsule);
655652
}
656653
else if (id == TYPE_NULL)
657654
{
@@ -841,8 +838,6 @@ PyObject * py_loader_impl_function_type_invoke(PyObject * self, PyObject * args)
841838
{
842839
static void * null_args[1] = { NULL };
843840

844-
loader_impl_py_function_type_invoke_state invoke_state = (loader_impl_py_function_type_invoke_state)PyModule_GetState(self);
845-
846841
signature s;
847842

848843
size_t args_size, args_count, min_args_size;
@@ -853,6 +848,8 @@ PyObject * py_loader_impl_function_type_invoke(PyObject * self, PyObject * args)
853848

854849
value ret;
855850

851+
loader_impl_py_function_type_invoke_state invoke_state = PyCapsule_GetPointer(self, NULL);
852+
856853
if (invoke_state == NULL)
857854
{
858855
log_write("metacall", LOG_LEVEL_ERROR, "Fatal error when invoking a function, state cannot be recovered, avoiding the function call");
@@ -1165,7 +1162,6 @@ int py_loader_impl_initialize_gc(loader_impl_py py_impl)
11651162
loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration config, loader_host host)
11661163
{
11671164
loader_impl_py py_impl;
1168-
loader_impl_py_function_type_invoke_state invoke_state;
11691165

11701166
PyGILState_STATE gstate;
11711167

@@ -1222,17 +1218,6 @@ loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration confi
12221218
return NULL;
12231219
}
12241220

1225-
/* Create module for allowing callbacks */
1226-
py_impl->function_type_invoke_mod = PyModule_Create(&py_loader_impl_function_type_invoke_module);
1227-
py_impl->function_type_invoke_func = PyObject_GetAttrString(py_impl->function_type_invoke_mod, PY_LOADER_IMPL_FUNCTION_TYPE_INVOKE_FUNC);
1228-
1229-
/* Store python loader into the module state */
1230-
invoke_state = (loader_impl_py_function_type_invoke_state)PyModule_GetState(py_impl->function_type_invoke_mod);
1231-
1232-
invoke_state->impl = impl;
1233-
invoke_state->py_impl = py_impl;
1234-
invoke_state->callback = NULL;
1235-
12361221
PyGILState_Release(gstate);
12371222

12381223
log_write("metacall", LOG_LEVEL_DEBUG, "Python loader initialized correctly");
@@ -1881,9 +1866,6 @@ int py_loader_impl_destroy(loader_impl impl)
18811866
}
18821867
#endif
18831868

1884-
Py_XDECREF(py_impl->function_type_invoke_mod);
1885-
Py_XDECREF(py_impl->function_type_invoke_func);
1886-
18871869
if (Py_IsInitialized() != 0)
18881870
{
18891871
if (PyErr_Occurred() != NULL)

source/ports/node_port/test/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ describe('metacall', () => {
159159

160160
// Opaque pointer for class instances
161161
assert.strictEqual(f.function_capsule_method(f.function_capsule_new_class()), 'hello world');
162+
163+
// Opaque pointer for class instances with callback
164+
assert.strictEqual(f.function_capsule_cb((klass) => f.function_capsule_method(klass)), 'hello world');
162165
});
163166
});
164167
});

0 commit comments

Comments
 (0)