/usr/lib/python2.7/dist-packages/numba/ccallback.py is in python-numba 0.34.0-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | """
Implementation of compiled C callbacks (@cfunc).
"""
from __future__ import print_function, division, absolute_import
import ctypes
from llvmlite import ir
from . import config, sigutils, utils, compiler
from .caching import NullCache, FunctionCache
from .dispatcher import _FunctionCompiler
from .targets import registry
from .typing import signature
from .typing.ctypes_utils import to_ctypes
class _CFuncCompiler(_FunctionCompiler):
def _customize_flags(self, flags):
flags.set('no_cpython_wrapper', True)
# Disable compilation of the IR module, because we first want to
# add the cfunc wrapper.
flags.set('no_compile', True)
# Object mode is not currently supported in C callbacks
# (no reliable way to get the environment)
flags.set('enable_pyobject', False)
if flags.force_pyobject:
raise NotImplementedError("object mode not allowed in C callbacks")
return flags
class CFunc(object):
"""
A compiled C callback, as created by the @cfunc decorator.
"""
_targetdescr = registry.cpu_target
def __init__(self, pyfunc, sig, locals, options):
args, return_type = sig
if return_type is None:
raise TypeError("C callback needs an explicit return type")
self.__name__ = pyfunc.__name__
self.__qualname__ = getattr(pyfunc, '__qualname__', self.__name__)
self.__wrapped__ = pyfunc
self._pyfunc = pyfunc
self._sig = signature(return_type, *args)
self._compiler = _CFuncCompiler(pyfunc, self._targetdescr,
options, locals)
self._wrapper_name = None
self._wrapper_address = None
self._cache = NullCache()
self._cache_hits = 0
def enable_caching(self):
self._cache = FunctionCache(self._pyfunc)
def compile(self):
# Use cache and compiler in a critical section
with compiler.lock_compiler:
# Try to load from cache
cres = self._cache.load_overload(self._sig, self._targetdescr.target_context)
if cres is None:
cres = self._compile_uncached()
self._cache.save_overload(self._sig, cres)
else:
self._cache_hits += 1
self._library = cres.library
self._wrapper_name = cres.fndesc.llvm_cfunc_wrapper_name
self._wrapper_address = self._library.get_pointer_to_function(self._wrapper_name)
def _compile_uncached(self):
sig = self._sig
# Compile native function
cres = self._compiler.compile(sig.args, sig.return_type)
assert not cres.objectmode # disabled by compiler above
fndesc = cres.fndesc
# Compile C wrapper
# Note we reuse the same library to allow inlining the Numba
# function inside the wrapper.
library = cres.library
module = library.create_ir_module(fndesc.unique_name)
context = cres.target_context
ll_argtypes = [context.get_value_type(ty) for ty in sig.args]
ll_return_type = context.get_value_type(sig.return_type)
wrapty = ir.FunctionType(ll_return_type, ll_argtypes)
wrapfn = module.add_function(wrapty, fndesc.llvm_cfunc_wrapper_name)
builder = ir.IRBuilder(wrapfn.append_basic_block('entry'))
self._build_c_wrapper(context, builder, cres, wrapfn.args)
library.add_ir_module(module)
library.finalize()
return cres
def _build_c_wrapper(self, context, builder, cres, c_args):
sig = self._sig
pyapi = context.get_python_api(builder)
fnty = context.call_conv.get_function_type(sig.return_type, sig.args)
fn = builder.module.add_function(fnty, cres.fndesc.llvm_func_name)
# XXX no obvious way to freeze an environment
status, out = context.call_conv.call_function(
builder, fn, sig.return_type, sig.args, c_args, env=None)
with builder.if_then(status.is_error, likely=False):
# If (and only if) an error occurred, acquire the GIL
# and use the interpreter to write out the exception.
gil_state = pyapi.gil_ensure()
context.call_conv.raise_error(builder, pyapi, status)
cstr = context.insert_const_string(builder.module, repr(self))
strobj = pyapi.string_from_string(cstr)
pyapi.err_write_unraisable(strobj)
pyapi.decref(strobj)
pyapi.gil_release(gil_state)
builder.ret(out)
@property
def native_name(self):
"""
The process-wide symbol the C callback is exposed as.
"""
# Note from our point of view, the C callback is the wrapper around
# the native function.
return self._wrapper_name
@property
def address(self):
"""
The address of the C callback.
"""
return self._wrapper_address
@utils.cached_property
def cffi(self):
"""
A cffi function pointer representing the C callback.
"""
import cffi
ffi = cffi.FFI()
# cffi compares types by name, so using precise types would risk
# spurious mismatches (such as "int32_t" vs. "int").
return ffi.cast("void *", self.address)
@utils.cached_property
def ctypes(self):
"""
A ctypes function object representing the C callback.
"""
ctypes_args = [to_ctypes(ty) for ty in self._sig.args]
ctypes_restype = to_ctypes(self._sig.return_type)
functype = ctypes.CFUNCTYPE(ctypes_restype, *ctypes_args)
return functype(self.address)
def inspect_llvm(self):
"""
Return the LLVM IR of the C callback definition.
"""
return self._library.get_llvm_str()
@property
def cache_hits(self):
return self._cache_hits
def __repr__(self):
return "<Numba C callback %r>" % (self.__qualname__,)
|