def generate_native_function(fn: FuncIR, emitter: Emitter, source_path: str, module_name: str) -> None: declarations = Emitter(emitter.context, fn.env) body = Emitter(emitter.context, fn.env) visitor = FunctionEmitterVisitor(body, declarations, fn.name, source_path, module_name) declarations.emit_line('{} {{'.format(native_function_header(fn, emitter))) body.indent() for r, i in fn.env.indexes.items(): if isinstance(r.type, RTuple): emitter.declare_tuple_struct(r.type) if i < len(fn.args): continue # skip the arguments ctype = emitter.ctype_spaced(r.type) declarations.emit_line('{ctype}{prefix}{name};'.format( ctype=ctype, prefix=REG_PREFIX, name=r.name)) # Before we emit the blocks, give them all labels for i, block in enumerate(fn.blocks): block.label = i for block in fn.blocks: body.emit_label(block) for op in block.ops: op.accept(visitor) body.emit_line('}') emitter.emit_from_emitter(declarations) emitter.emit_from_emitter(body)
def generate_wrapper_core(fn: FuncIR, emitter: Emitter, optional_args: Optional[List[RuntimeArg]] = None, arg_names: Optional[List[str]] = None, cleanups: Optional[List[str]] = None, traceback_code: Optional[str] = None) -> None: """Generates the core part of a wrapper function for a native function. This expects each argument as a PyObject * named obj_{arg} as a precondition. It converts the PyObject *s to the necessary types, checking and unboxing if necessary, makes the call, then boxes the result if necessary and returns it. """ optional_args = optional_args or [] cleanups = cleanups or [] use_goto = bool(cleanups or traceback_code) error_code = 'return NULL;' if not use_goto else 'goto fail;' arg_names = arg_names or [arg.name for arg in fn.args] for arg_name, arg in zip(arg_names, fn.args): # Suppress the argument check for *args/**kwargs, since we know it must be right. typ = arg.type if arg.kind not in (ARG_STAR, ARG_STAR2) else object_rprimitive generate_arg_check(arg_name, typ, emitter, error_code, arg in optional_args) native_args = ', '.join('arg_{}'.format(arg) for arg in arg_names) if fn.ret_type.is_unboxed or use_goto: # TODO: The Py_RETURN macros return the correct PyObject * with reference count handling. # Are they relevant? emitter.emit_line('{}retval = {}{}({});'.format( emitter.ctype_spaced(fn.ret_type), NATIVE_PREFIX, fn.cname(emitter.names), native_args)) emitter.emit_lines(*cleanups) if fn.ret_type.is_unboxed: emitter.emit_error_check('retval', fn.ret_type, 'return NULL;') emitter.emit_box('retval', 'retbox', fn.ret_type, declare_dest=True) emitter.emit_line('return {};'.format( 'retbox' if fn.ret_type.is_unboxed else 'retval')) else: emitter.emit_line('return {}{}({});'.format(NATIVE_PREFIX, fn.cname(emitter.names), native_args)) # TODO: Tracebacks? if use_goto: emitter.emit_label('fail') emitter.emit_lines(*cleanups) if traceback_code: emitter.emit_lines(traceback_code) emitter.emit_lines('return NULL;')
def generate_native_function(fn: FuncIR, emitter: Emitter) -> None: declarations = Emitter(emitter.context, fn.env) body = Emitter(emitter.context, fn.env) visitor = FunctionEmitterVisitor(body, declarations) declarations.emit_line('{} {{'.format(native_function_header(fn))) body.indent() for i in range(len(fn.args), fn.env.num_regs()): ctype = fn.env.types[i].ctype declarations.emit_line('{ctype} {prefix}{name};'.format( ctype=ctype, prefix=REG_PREFIX, name=fn.env.names[i])) for block in fn.blocks: body.emit_label(block.label) for op in block.ops: op.accept(visitor) body.emit_line('}') emitter.emit_from_emitter(declarations) emitter.emit_from_emitter(body)