Exemple #1
0
    def emit_box(self,
                 src: str,
                 dest: str,
                 typ: RType,
                 declare_dest: bool = False,
                 can_borrow: bool = False) -> None:
        """Emit code for boxing a value of given type.

        Generate a simple assignment if no boxing is needed.

        The source reference count is stolen for the result (no need to decref afterwards).
        """
        # TODO: Always generate a new reference (if a reference type)
        if declare_dest:
            declaration = 'PyObject *'
        else:
            declaration = ''
        if is_int_rprimitive(typ) or is_short_int_rprimitive(typ):
            # Steal the existing reference if it exists.
            self.emit_line('{}{} = CPyTagged_StealAsObject({});'.format(
                declaration, dest, src))
        elif is_bool_rprimitive(typ):
            # N.B: bool is special cased to produce a borrowed value
            # after boxing, so we don't need to increment the refcount
            # when this comes directly from a Box op.
            self.emit_lines('{}{} = {} ? Py_True : Py_False;'.format(
                declaration, dest, src))
            if not can_borrow:
                self.emit_inc_ref(dest, object_rprimitive)
        elif is_none_rprimitive(typ):
            # N.B: None is special cased to produce a borrowed value
            # after boxing, so we don't need to increment the refcount
            # when this comes directly from a Box op.
            self.emit_lines('{}{} = Py_None;'.format(declaration, dest))
            if not can_borrow:
                self.emit_inc_ref(dest, object_rprimitive)
        elif isinstance(typ, RTuple):
            self.declare_tuple_struct(typ)
            self.emit_line('{}{} = PyTuple_New({});'.format(
                declaration, dest, len(typ.types)))
            self.emit_line('if (unlikely({} == NULL))'.format(dest))
            self.emit_line('    CPyError_OutOfMemory();')
            # TODO: Fail if dest is None
            for i in range(0, len(typ.types)):
                if not typ.is_unboxed:
                    self.emit_line('PyTuple_SET_ITEM({}, {}, {}.f{}'.format(
                        dest, i, src, i))
                else:
                    inner_name = self.temp_name()
                    self.emit_box('{}.f{}'.format(src, i),
                                  inner_name,
                                  typ.types[i],
                                  declare_dest=True)
                    self.emit_line('PyTuple_SET_ITEM({}, {}, {});'.format(
                        dest, i, inner_name))
        else:
            assert not typ.is_unboxed
            # Type is boxed -- trivially just assign.
            self.emit_line('{}{} = {};'.format(declaration, dest, src))
Exemple #2
0
    def gen_step(self) -> None:
        builder = self.builder
        line = self.line

        # Increment index register. If the range is known to fit in short ints, use
        # short ints.
        if (is_short_int_rprimitive(self.start_reg.type)
                and is_short_int_rprimitive(self.end_reg.type)):
            new_val = builder.primitive_op(
                unsafe_short_add, [builder.read(self.index_reg, line),
                                   builder.add(LoadInt(self.step))], line)

        else:
            new_val = builder.binary_op(
                builder.read(self.index_reg, line), builder.add(LoadInt(self.step)), '+', line)
        builder.assign(self.index_reg, new_val, line)
        builder.assign(self.index_target, new_val, line)
Exemple #3
0
 def visit_rprimitive(self, left: RPrimitive) -> bool:
     if is_short_int_rprimitive(left) and is_int_rprimitive(self.right):
         return True
     return left is self.right
Exemple #4
0
    def emit_unbox(self,
                   src: str,
                   dest: str,
                   typ: RType,
                   custom_failure: Optional[str] = None,
                   declare_dest: bool = False,
                   borrow: bool = False,
                   optional: bool = False) -> None:
        """Emit code for unboxing a value of given type (from PyObject *).

        Evaluate C code in 'failure' if the value has an incompatible type.

        Always generate a new reference.

        Args:
            src: Name of source C variable
            dest: Name of target C variable
            typ: Type of value
            failure: What happens on error
            declare_dest: If True, also declare the variable 'dest'
            borrow: If True, create a borrowed reference
        """
        # TODO: Verify refcount handling.
        raise_exc = 'CPy_TypeError("{}", {});'.format(self.pretty_name(typ),
                                                      src)
        if custom_failure is not None:
            failure = [raise_exc, custom_failure]
        else:
            failure = [raise_exc, '%s = %s;' % (dest, self.c_error_value(typ))]
        if is_int_rprimitive(typ) or is_short_int_rprimitive(typ):
            if declare_dest:
                self.emit_line('CPyTagged {};'.format(dest))
            self.emit_arg_check(src, dest, typ,
                                '(likely(PyLong_Check({})))'.format(src),
                                optional)
            if borrow:
                self.emit_line(
                    '    {} = CPyTagged_BorrowFromObject({});'.format(
                        dest, src))
            else:
                self.emit_line('    {} = CPyTagged_FromObject({});'.format(
                    dest, src))
            self.emit_line('else {')
            self.emit_lines(*failure)
            self.emit_line('}')
        elif is_bool_rprimitive(typ):
            # Whether we are borrowing or not makes no difference.
            if declare_dest:
                self.emit_line('char {};'.format(dest))
            self.emit_arg_check(src, dest, typ,
                                '(unlikely(!PyBool_Check({}))) {{'.format(src),
                                optional)
            self.emit_lines(*failure)
            self.emit_line('} else')
            conversion = '{} == Py_True'.format(src)
            self.emit_line('    {} = {};'.format(dest, conversion))
        elif is_none_rprimitive(typ):
            # Whether we are borrowing or not makes no difference.
            if declare_dest:
                self.emit_line('char {};'.format(dest))
            self.emit_arg_check(src, dest, typ,
                                '(unlikely({} != Py_None)) {{'.format(src),
                                optional)
            self.emit_lines(*failure)
            self.emit_line('} else')
            self.emit_line('    {} = 1;'.format(dest))
        elif isinstance(typ, RTuple):
            self.declare_tuple_struct(typ)
            if declare_dest:
                self.emit_line('{} {};'.format(self.ctype(typ), dest))
            # HACK: The error handling for unboxing tuples is busted
            # and instead of fixing it I am just wrapping it in the
            # cast code which I think is right. This is not good.
            if optional:
                self.emit_line('if ({} == NULL) {{'.format(src))
                self.emit_line('{} = {};'.format(dest,
                                                 self.c_error_value(typ)))
                self.emit_line('} else {')

            cast_temp = self.temp_name()
            self.emit_tuple_cast(src,
                                 cast_temp,
                                 typ,
                                 declare_dest=True,
                                 err='',
                                 src_type=None)
            self.emit_line('if (unlikely({} == NULL)) {{'.format(cast_temp))

            # self.emit_arg_check(src, dest, typ,
            #     '(!PyTuple_Check({}) || PyTuple_Size({}) != {}) {{'.format(
            #         src, src, len(typ.types)), optional)
            self.emit_lines(*failure)  # TODO: Decrease refcount?
            self.emit_line('} else {')
            if not typ.types:
                self.emit_line('{}.empty_struct_error_flag = 0;'.format(dest))
            for i, item_type in enumerate(typ.types):
                temp = self.temp_name()
                # emit_tuple_cast above checks the size, so this should not fail
                self.emit_line(
                    'PyObject *{} = PyTuple_GET_ITEM({}, {});'.format(
                        temp, src, i))
                temp2 = self.temp_name()
                # Unbox or check the item.
                if item_type.is_unboxed:
                    self.emit_unbox(temp,
                                    temp2,
                                    item_type,
                                    custom_failure,
                                    declare_dest=True,
                                    borrow=borrow)
                else:
                    if not borrow:
                        self.emit_inc_ref(temp, object_rprimitive)
                    self.emit_cast(temp, temp2, item_type, declare_dest=True)
                self.emit_line('{}.f{} = {};'.format(dest, i, temp2))
            self.emit_line('}')
            if optional:
                self.emit_line('}')

        else:
            assert False, 'Unboxing not implemented: %s' % typ