def split_blocks_at_errors(blocks: List[BasicBlock],
                           default_error_handler: BasicBlock,
                           func_name: Optional[str]) -> List[BasicBlock]:
    new_blocks = []  # type: List[BasicBlock]

    # First split blocks on ops that may raise.
    for block in blocks:
        ops = block.ops
        block.ops = []
        cur_block = block
        new_blocks.append(cur_block)

        # If the block has an error handler specified, use it. Otherwise
        # fall back to the default.
        error_label = block.error_handler or default_error_handler
        block.error_handler = None

        for op in ops:
            target = op  # type: Value
            cur_block.ops.append(op)
            if isinstance(op, RegisterOp) and op.error_kind != ERR_NEVER:
                # Split
                new_block = BasicBlock()
                new_blocks.append(new_block)

                if op.error_kind == ERR_MAGIC:
                    # Op returns an error value on error that depends on result RType.
                    variant = Branch.IS_ERROR
                    negated = False
                elif op.error_kind == ERR_FALSE:
                    # Op returns a C false value on error.
                    variant = Branch.BOOL
                    negated = True
                elif op.error_kind == ERR_ALWAYS:
                    variant = Branch.BOOL
                    negated = True
                    # this is a hack to represent the always fail
                    # semantics, using a temporary bool with value false
                    target = Integer(0, bool_rprimitive)
                else:
                    assert False, 'unknown error kind %d' % op.error_kind

                # Void ops can't generate errors since error is always
                # indicated by a special value stored in a register.
                if op.error_kind != ERR_ALWAYS:
                    assert not op.is_void, "void op generating errors?"

                branch = Branch(target,
                                true_label=error_label,
                                false_label=new_block,
                                op=variant,
                                line=op.line)
                branch.negated = negated
                if op.line != NO_TRACEBACK_LINE_NO and func_name is not None:
                    branch.traceback_entry = (func_name, op.line)
                cur_block.ops.append(branch)
                cur_block = new_block

    return new_blocks
예제 #2
0
 def test_get_attr_merged(self) -> None:
     op = GetAttr(self.r, 'y', 1)
     branch = Branch(op, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
     branch.traceback_entry = ('foobar', 123)
     self.assert_emit(op,
                      """\
         cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_y;
         if (unlikely(cpy_r_r0 == CPY_INT_TAG)) {
             CPy_AttributeError("prog.py", "foobar", "A", "y", 123, CPyStatic_prog___globals);
             goto CPyL8;
         }
         CPyTagged_INCREF(cpy_r_r0);
         goto CPyL9;
         """,
                      next_branch=branch)
예제 #3
0
 def test_cast_and_branch_no_merge_3(self) -> None:
     op = Cast(self.r, dict_rprimitive, 1)
     next_block = BasicBlock(9)
     branch = Branch(op, BasicBlock(8), next_block, Branch.BOOL)
     branch.traceback_entry = ('foobar', 123)
     self.assert_emit(
         op,
         """\
         if (likely(PyDict_Check(cpy_r_r)))
             cpy_r_r0 = cpy_r_r;
         else {
             CPy_TypeError("dict", cpy_r_r);
             cpy_r_r0 = NULL;
         }
         """,
         next_block=next_block,
         next_branch=branch,
     )
예제 #4
0
    def test_cast_and_branch_merge(self) -> None:
        op = Cast(self.r, dict_rprimitive, 1)
        next_block = BasicBlock(9)
        branch = Branch(op, BasicBlock(8), next_block, Branch.IS_ERROR)
        branch.traceback_entry = ('foobar', 123)
        self.assert_emit(
            op,
            """\
if (likely(PyDict_Check(cpy_r_r)))
    cpy_r_r0 = cpy_r_r;
else {
    CPy_TypeErrorTraceback("prog.py", "foobar", 123, CPyStatic_prog___globals, "dict", cpy_r_r);
    goto CPyL8;
}
""",
            next_block=next_block,
            next_branch=branch,
            skip_next=True,
        )