def __call__(self, *args, **kwargs): from flypy.representation import byref, stack_allocate from flypy.conversion import (toctypes, fromctypes, toobject, fromobject, ctype) #from flypy.support.ctypes_support import CTypesStruct #from flypy.types import Function # Keep this alive for the duration of the call keepalive = list(args) + list(kwargs.values()) # Order arguments args = flatargs(self.py_func, args, kwargs) # Translate cfunc, restype = self.translate([typeof(x) for x in args.flat]) # Construct flypy values argtypes = [typeof(x) for x in args] arg_objs = list(starmap(fromobject, zip(args, argtypes))) # Map flypy values to a ctypes representation args = [] for arg, argtype in zip(arg_objs, argtypes): c_arg = toctypes(arg, argtype, keepalive) if byref(argtype) and stack_allocate(argtype): c_arg = ctypes.pointer(c_arg) args.append(c_arg) # We need this cast since the ctypes function constructed from LLVM # IR has different structs (which are structurally equivalent) c_restype = ctype(restype) if byref(restype): c_result = c_restype() # dummy result value args.append(ctypes.pointer(c_result)) c_restype = None # void c_signature = ctypes.PYFUNCTYPE(c_restype, *[type(arg) for arg in args]) cfunc = ctypes.cast(cfunc, c_signature) # Handle calling convention if byref(restype): cfunc(*args) else: c_result = cfunc(*args) # Map ctypes result back to a python value result = fromctypes(c_result, restype) result_obj = toobject(result, restype) return result_obj
def __call__(self, *args, **kwargs): from flypy.representation import byref, stack_allocate from flypy.conversion import ( toctypes, fromctypes, toobject, fromobject, ctype) #from flypy.support.ctypes_support import CTypesStruct #from flypy.types import Function # Keep this alive for the duration of the call keepalive = list(args) + list(kwargs.values()) # Order arguments args = flatargs(self.py_func, args, kwargs) # Translate cfunc, restype = self.translate([typeof(x) for x in args.flat]) # Construct flypy values argtypes = [typeof(x) for x in args] arg_objs = list(starmap(fromobject, zip(args, argtypes))) # Map flypy values to a ctypes representation args = [] for arg, argtype in zip(arg_objs, argtypes): c_arg = toctypes(arg, argtype, keepalive) if byref(argtype) and stack_allocate(argtype): c_arg = ctypes.pointer(c_arg) args.append(c_arg) # We need this cast since the ctypes function constructed from LLVM # IR has different structs (which are structurally equivalent) c_restype = ctype(restype) if byref(restype): c_result = c_restype() # dummy result value args.append(ctypes.pointer(c_result)) c_restype = None # void c_signature = ctypes.PYFUNCTYPE(c_restype, *[type(arg) for arg in args]) cfunc = ctypes.cast(cfunc, c_signature) # Handle calling convention if byref(restype): cfunc(*args) else: c_result = cfunc(*args) # Map ctypes result back to a python value result = fromctypes(c_result, restype) result_obj = toobject(result, restype) return result_obj
def rewrite_obj_return(func, env): """ Handle returning stack-allocated objects. """ if should_skip(env): return context = env['flypy.typing.context'] restype = env['flypy.typing.restype'] envs = env['flypy.state.envs'] builder = Builder(func) stack_alloc = representation.byref(restype) if stack_alloc: out = func.add_arg(func.temp("out"), opaque_t) context[out] = Pointer[restype] func.type = types.Function(types.Void, func.type.argtypes, False) for arg in func.args: arg.type = opaque_t func.type = types.Function(func.type.restype, (opaque_t, ) * len(func.args), False) is_generator = env['flypy.state.generator'] for op in func.ops: if (op.opcode == 'ret' and op.args[0] is not None and stack_alloc and not is_generator): # ret val => # store (load val) out ; ret void [val] = op.args builder.position_before(op) newval = builder.load(val) builder.store(newval, out) op.set_args([None]) # Update context context[newval] = StackVar[context[val]] elif op.opcode == 'call' and op.type != types.Void: # result = call(f, ...) => # alloca result ; call(f, ..., &result) ty = context[op] if conversion.byref(ty): f, args = op.args if not is_flypy_cc(f) or should_skip(envs[f]): continue builder.position_before(op) retval = builder.alloca(opaque_t) builder.position_after(op) op.replace_uses(retval) newargs = args + [retval] op.set_args([f, newargs]) # Update context context[retval] = context[op] context[op] = void
def rewrite_obj_return(func, env): """ Handle returning stack-allocated objects. """ if should_skip(env): return context = env['flypy.typing.context'] restype = env['flypy.typing.restype'] envs = env['flypy.state.envs'] builder = Builder(func) stack_alloc = representation.byref(restype) if stack_alloc: out = func.add_arg(func.temp("out"), opaque_t) context[out] = Pointer[restype] func.type = types.Function(types.Void, func.type.argtypes, False) for arg in func.args: arg.type = opaque_t func.type = types.Function(func.type.restype, (opaque_t,) * len(func.args), False) is_generator = env['flypy.state.generator'] for op in func.ops: if (op.opcode == 'ret' and op.args[0] is not None and stack_alloc and not is_generator): # ret val => # store (load val) out ; ret void [val] = op.args builder.position_before(op) newval = builder.load(val) builder.store(newval, out) op.set_args([None]) # Update context context[newval] = StackVar[context[val]] elif op.opcode == 'call' and op.type != types.Void: # result = call(f, ...) => # alloca result ; call(f, ..., &result) ty = context[op] if conversion.byref(ty): f, args = op.args if not is_flypy_cc(f) or should_skip(envs[f]): continue builder.position_before(op) retval = builder.alloca(opaque_t) builder.position_after(op) op.replace_uses(retval) newargs = args + [retval] op.set_args([f, newargs]) # Update context context[retval] = context[op] context[op] = void
def ctype(cls, ty): restype = ctype(ty.restype) argtypes = [ctype(argtype) for argtype in ty.argtypes] if byref(ty.restype): argtypes.append(ctypes.POINTER(restype)) restype = None # void return ctypes.POINTER(ctypes.PYFUNCTYPE(restype, *argtypes))
def rewrite_constants(func, env): """ Rewrite constants with user-defined types to IR constants. Also rewrite constants of builtins to instances of flypy classes. e.g. constant(None) -> constant(NoneValue) constant("foo") -> constant(Bytes("foo")) """ if env['flypy.state.opaque']: return context = env['flypy.typing.context'] for op in func.ops: if op.opcode == 'exc_catch': continue constants = collect_constants(op) new_constants = [] for c in constants: ty = context[c] # Python -> flypy (if not already) flypy_obj = fromobject(c.const, ty) # flypy -> ctypes ctype_obj = toctypes(flypy_obj, ty, _keep_alive) if byref(ty): ctype_obj = ctypes.pointer(ctype_obj) # ctypes -> pykit new_const = from_ctypes_value(ctype_obj) context[new_const] = ty new_constants.append(new_const) _keep_alive.extend([ctype_obj, c.const]) substitute_args(op, constants, new_constants)
def rewrite_constants(func, env): """ Rewrite constants with user-defined types to IR constants. Also rewrite constants of builtins to instances of flypy classes. e.g. constant(None) -> constant(NoneValue) constant("foo") -> constant(Bytes("foo")) """ if env['flypy.state.opaque']: return context = env['flypy.typing.context'] for op in func.ops: if op.opcode == 'exc_catch': continue constants = collect_constants(op) new_constants = [] for c in constants: ty = context[c] # Python -> flypy (if not already) flypy_obj = fromobject(c.const, ty, _keep_alive) # flypy -> ctypes ctype_obj = toctypes(flypy_obj, ty, _keep_alive) if byref(ty): ctype_obj = ctypes.pointer(ctype_obj) # ctypes -> pykit new_const = from_ctypes_value(ctype_obj) context[new_const] = ty new_constants.append(new_const) _keep_alive.extend([ctype_obj, c.const]) substitute_args(op, constants, new_constants)