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): ...@@ -4053,15 +4053,18 @@ class PyCFunctionNode(ExprNode):
# #
# pymethdef_cname string PyMethodDef structure # pymethdef_cname string PyMethodDef structure
# self_object ExprNode or None # self_object ExprNode or None
# binding bool
subexprs = [] subexprs = []
self_object = None self_object = None
binding = False
type = py_object_type type = py_object_type
is_temp = 1 is_temp = 1
def analyse_types(self, env): def analyse_types(self, env):
pass if self.binding:
env.use_utility_code(binding_cfunc_utility_code)
gil_message = "Constructing Python function" gil_message = "Constructing Python function"
...@@ -4073,9 +4076,14 @@ class PyCFunctionNode(ExprNode): ...@@ -4073,9 +4076,14 @@ class PyCFunctionNode(ExprNode):
return self_result return self_result
def generate_result_code(self, code): def generate_result_code(self, code):
if self.binding:
constructor = "%s_New" % Naming.binding_cfunc
else:
constructor = "PyCFunction_New"
code.putln( code.putln(
"%s = PyCFunction_New(&%s, %s); %s" % ( "%s = %s(&%s, %s); %s" % (
self.result(), self.result(),
constructor,
self.pymethdef_cname, self.pymethdef_cname,
self.self_result_code(), self.self_result_code(),
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
...@@ -4084,6 +4092,8 @@ class PyCFunctionNode(ExprNode): ...@@ -4084,6 +4092,8 @@ class PyCFunctionNode(ExprNode):
class InnerFunctionNode(PyCFunctionNode): class InnerFunctionNode(PyCFunctionNode):
# Special PyCFunctionNode that depends on a closure class # Special PyCFunctionNode that depends on a closure class
# #
binding = True
def self_result_code(self): def self_result_code(self):
return "((PyObject*)%s)" % Naming.cur_scope_cname return "((PyObject*)%s)" % Naming.cur_scope_cname
...@@ -6652,3 +6662,62 @@ proto=""" ...@@ -6652,3 +6662,62 @@ proto="""
#define UNARY_NEG_WOULD_OVERFLOW(x) \ #define UNARY_NEG_WOULD_OVERFLOW(x) \
(((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(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__)
...@@ -1675,6 +1675,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1675,6 +1675,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))); 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("#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 ---*/") code.putln("/*--- Library function declarations ---*/")
env.generate_library_function_declarations(code) env.generate_library_function_declarations(code)
......
...@@ -89,6 +89,7 @@ cur_scope_cname = pyrex_prefix + "cur_scope" ...@@ -89,6 +89,7 @@ cur_scope_cname = pyrex_prefix + "cur_scope"
enc_scope_cname = pyrex_prefix + "enc_scope" enc_scope_cname = pyrex_prefix + "enc_scope"
frame_cname = pyrex_prefix + "frame" frame_cname = pyrex_prefix + "frame"
frame_code_cname = pyrex_prefix + "frame_code" frame_code_cname = pyrex_prefix + "frame_code"
binding_cfunc = pyrex_prefix + "binding_PyCFunctionType"
line_c_macro = "__LINE__" line_c_macro = "__LINE__"
......
...@@ -1635,6 +1635,7 @@ class DefNode(FuncDefNode): ...@@ -1635,6 +1635,7 @@ class DefNode(FuncDefNode):
# name string the Python name of the function # name string the Python name of the function
# lambda_name string the internal name of a lambda 'function' # lambda_name string the internal name of a lambda 'function'
# decorators [DecoratorNode] list of decorators # decorators [DecoratorNode] list of decorators
# binding bool bind like a Python function
# args [CArgDeclNode] formal arguments # args [CArgDeclNode] formal arguments
# star_arg PyArgDeclNode or None * argument # star_arg PyArgDeclNode or None * argument
# starstar_arg PyArgDeclNode or None ** argument # starstar_arg PyArgDeclNode or None ** argument
...@@ -1661,6 +1662,7 @@ class DefNode(FuncDefNode): ...@@ -1661,6 +1662,7 @@ class DefNode(FuncDefNode):
entry = None entry = None
acquire_gil = 0 acquire_gil = 0
self_in_stararg = 0 self_in_stararg = 0
binding = False
def __init__(self, pos, **kwds): def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds) FuncDefNode.__init__(self, pos, **kwds)
...@@ -1973,6 +1975,9 @@ class DefNode(FuncDefNode): ...@@ -1973,6 +1975,9 @@ class DefNode(FuncDefNode):
elif env.is_closure_scope: elif env.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode( rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname) 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, self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name), lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs) 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