Commit 6d66c50b authored by Robert Bradshaw's avatar Robert Bradshaw

Binding PyCFunction type.

This is a bit hackish, but creating a wrapper type would be as well, but
would also have a performance penalty.
parent d18a809b
......@@ -4053,15 +4053,18 @@ class PyCFunctionNode(ExprNode):
#
# pymethdef_cname string PyMethodDef structure
# self_object ExprNode or None
# binding bool
subexprs = []
self_object = None
binding = False
type = py_object_type
is_temp = 1
def analyse_types(self, env):
pass
if self.binding:
env.use_utility_code(binding_cfunc_utility_code)
gil_message = "Constructing Python function"
......@@ -4073,9 +4076,14 @@ class PyCFunctionNode(ExprNode):
return self_result
def generate_result_code(self, code):
if self.binding:
constructor = "%s_New" % Naming.binding_cfunc
else:
constructor = "PyCFunction_New"
code.putln(
"%s = PyCFunction_New(&%s, %s); %s" % (
"%s = %s(&%s, %s); %s" % (
self.result(),
constructor,
self.pymethdef_cname,
self.self_result_code(),
code.error_goto_if_null(self.result(), self.pos)))
......@@ -4084,6 +4092,8 @@ class PyCFunctionNode(ExprNode):
class InnerFunctionNode(PyCFunctionNode):
# Special PyCFunctionNode that depends on a closure class
#
binding = True
def self_result_code(self):
return "((PyObject*)%s)" % Naming.cur_scope_cname
......@@ -6652,3 +6662,62 @@ proto="""
#define UNARY_NEG_WOULD_OVERFLOW(x) \
(((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x)))
""")
binding_cfunc_utility_code = UtilityCode(
proto="""
#define %(binding_cfunc)s_USED 1
typedef struct {
PyCFunctionObject func;
} %(binding_cfunc)s_object;
PyTypeObject %(binding_cfunc)s_type;
PyTypeObject *%(binding_cfunc)s = NULL;
PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */
#define %(binding_cfunc)s_New(ml, self) %(binding_cfunc)s_NewEx(ml, self, NULL)
int %(binding_cfunc)s_init(void); /* proto */
""" % Naming.__dict__,
impl="""
PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
%(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s);
if (op == NULL)
return NULL;
op->func.m_ml = ml;
Py_XINCREF(self);
op->func.m_self = self;
Py_XINCREF(module);
op->func.m_module = module;
_PyObject_GC_TRACK(op);
return (PyObject *)op;
}
static void %(binding_cfunc)s_dealloc(%(binding_cfunc)s_object *m) {
_PyObject_GC_UNTRACK(m);
Py_XDECREF(m->func.m_self);
Py_XDECREF(m->func.m_module);
PyObject_GC_Del(m);
}
static PyObject *%(binding_cfunc)s_descr_get(PyObject *func, PyObject *obj, PyObject *type) {
if (obj == Py_None)
obj = NULL;
return PyMethod_New(func, obj, type);
}
int %(binding_cfunc)s_init(void) {
%(binding_cfunc)s_type = PyCFunction_Type;
%(binding_cfunc)s_type.tp_name = "cython_binding_builtin_function_or_method";
%(binding_cfunc)s_type.tp_dealloc = (destructor)%(binding_cfunc)s_dealloc;
%(binding_cfunc)s_type.tp_descr_get = %(binding_cfunc)s_descr_get;
if (PyType_Ready(&%(binding_cfunc)s_type) < 0) {
return -1;
}
%(binding_cfunc)s = &%(binding_cfunc)s_type;
return 0;
}
""" % Naming.__dict__)
......@@ -1674,6 +1674,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#else");
code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos)));
code.putln("#endif");
code.putln("#ifdef %s_USED" % Naming.binding_cfunc)
code.putln("if (%s_init() < 0) %s" % (Naming.binding_cfunc, code.error_goto(self.pos)))
code.putln("#endif")
code.putln("/*--- Library function declarations ---*/")
env.generate_library_function_declarations(code)
......
......@@ -89,6 +89,7 @@ cur_scope_cname = pyrex_prefix + "cur_scope"
enc_scope_cname = pyrex_prefix + "enc_scope"
frame_cname = pyrex_prefix + "frame"
frame_code_cname = pyrex_prefix + "frame_code"
binding_cfunc = pyrex_prefix + "binding_PyCFunctionType"
line_c_macro = "__LINE__"
......
......@@ -1635,6 +1635,7 @@ class DefNode(FuncDefNode):
# name string the Python name of the function
# lambda_name string the internal name of a lambda 'function'
# decorators [DecoratorNode] list of decorators
# binding bool bind like a Python function
# args [CArgDeclNode] formal arguments
# star_arg PyArgDeclNode or None * argument
# starstar_arg PyArgDeclNode or None ** argument
......@@ -1661,6 +1662,7 @@ class DefNode(FuncDefNode):
entry = None
acquire_gil = 0
self_in_stararg = 0
binding = False
def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds)
......@@ -1973,6 +1975,9 @@ class DefNode(FuncDefNode):
elif env.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname)
else:
rhs = ExprNodes.PyCFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = self.binding)
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs)
......
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