<commit_before>from __future__ import print_function, division, absolute_import

from llvmlite.llvmpy.core import Type, Builder, Constant
import llvmlite.llvmpy.core as lc

from numba import types, cgutils, errcode


class _ArgManager(object):
    """
    A utility class to handle argument unboxing and cleanup
    """
    def __init__(self, builder, api, nargs):
        self.builder = builder
        self.api = api
        self.arg_count = 0  # how many function arguments have been processed
        self.cleanups = []

        # set up switch for error processing of function arguments
        self.elseblk = cgutils.append_basic_block(self.builder, "arg.ok")
        with cgutils.goto_block(self.builder, self.elseblk):
            self.builder.ret(self.api.get_null_object())

        self.swtblk = cgutils.append_basic_block(self.builder, ".arg.err")
        with cgutils.goto_block(self.builder, self.swtblk):
            self.swt_val = cgutils.alloca_once(self.builder, Type.int(32))
            self.swt = self.builder.switch(self.builder.load(self.swt_val),
                                           self.elseblk, nargs)

        self.prev = self.elseblk

    def add_arg(self, obj, ty):
        """
        Unbox argument and emit code that handles any error during unboxing
        """
        # Unbox argument
        val, dtor = self.api.to_native_arg(self.builder.load(obj), ty)
        self.cleanups.append(dtor)
        # add to the switch each time through the loop
        # prev and cur are references to keep track of which block to branch to

        if self.arg_count == 0:
            bb = cgutils.append_basic_block(self.builder,
                                            "arg%d.err" % self.arg_count)
            self.cur = bb
            self.swt.add_case(Constant.int(Type.int(32), self.arg_count), bb)
        else:
            # keep a reference to the previous arg.error block
            self.prev = self.cur
            bb = cgutils.append_basic_block(self.builder,
                                            "arg%d.error" % self.arg_count)
            self.cur = bb
            self.swt.add_case(Constant.int(Type.int(32), self.arg_count), bb)

        # write the error block
        with cgutils.goto_block(self.builder, self.cur):
            dtor()
            self.builder.branch(self.prev)

        # store arg count into value to switch on if there is an error
        self.builder.store(Constant.int(Type.int(32), self.arg_count),
                           self.swt_val)

        # check for Python C-API Error
        error_check = self.api.err_occurred()
        err_happened = self.builder.icmp(lc.ICMP_NE, error_check,
                                         self.api.get_null_object())
        # if error occurs -- clean up -- goto switch block
        with cgutils.if_unlikely(self.builder, err_happened):
            self.builder.branch(self.swtblk)

        self.arg_count += 1
        return val

    def emit_cleanup(self):
        """Emit the cleanup code after we are done with the arguments
        """
        for dtor in self.cleanups:
            dtor()


class PyCallWrapper(object):
    def __init__(self, context, module, func, fndesc, exceptions):
        self.context = context
        self.module = module
        self.func = func
        self.fndesc = fndesc
        self.exceptions = exceptions

    def build(self):
        wrapname = "wrapper.%s" % self.func.name<commit_msg>Fix control flow of cleanup for unboxing failure<commit_after>from __future__ import print_function, division, absolute_import

from llvmlite.llvmpy.core import Type, Builder, Constant
import llvmlite.llvmpy.core as lc

from numba import types, cgutils, errcode


class _ArgManager(object):
    """
    A utility class to handle argument unboxing and cleanup
    """
    def __init__(self, builder, api, nargs):
        self.builder = builder
        self.api = api
        self.arg_count = 0  # how many function arguments have been processed
        self.cleanups = []

        # Block that returns after erroneous argument unboxing/cleanup
        self.endblk = cgutils.append_basic_block(self.builder, "arg.end")
        with cgutils.goto_block(self.builder, self.endblk):
            self.builder.ret(self.api.get_null_object())

        self.nextblk = self.endblk

    def add_arg(self, obj, ty):
        """
        Unbox argument and emit code that handles any error during unboxing.
        Args are cleaned up in reverse order of the parameter list, and
        cleanup begins as soon as unboxing of any argument fails. E.g. failure
        on arg2 will result in control flow going through:

            arg2.err -> arg1.err -> arg0.err -> arg.end (returns)
        """
        # Unbox argument
        val, dtor = self.api.to_native_arg(self.builder.load(obj), ty)

        # check for Python C-API Error
        error_check = self.api.err_occurred()
        err_happened = self.builder.icmp(lc.ICMP_NE, error_check,
                                         self.api.get_null_object())

        # Write the cleanup block
        cleanupblk = cgutils.append_basic_block(self.builder,
                                                "arg%d.err" % self.arg_count)
        with cgutils.goto_block(self.builder, cleanupblk):
            dtor()
            # Go to next cleanup block
            self.builder.branch(self.nextblk)

        # If an error occurred, go to the cleanup block
        with cgutils.if_unlikely(self.builder, err_happened):
            self.builder.branch(cleanupblk)

        self.cleanups.append(dtor)
        self.nextblk = cleanupblk
        self.arg_count += 1
        return val

    def emit_cleanup(self):
        """Emit the cleanup code after we are done with the arguments
        """
        for dtor in self.cleanups:
            dtor()


class PyCallWrapper(object):
    def __init__(self, context, module, func, fndesc, exceptions):
        self.context = context
        self.module = module
        self.func = func
        self.fndesc = fndesc
        self.exceptions = exceptions

    def build(self):
        wrapname = "wrapper.%s" % self.func.name
{'fraction_non_alphanumeric': 0.08745123537061118, 'fraction_numerical': 0.0027633289986996098, 'mean_word_length': 2.0657698056801195, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6919031', 'n_tokens_mistral': 1786, 'n_tokens_neox': 1739, 'n_words': 478}