예제 #1
0
 def add_buffer_size():
     size_expr = size_to_bytes(compute_buffer_size(type, original_type),
                               type)
     return Expr(copy_pred(argument)).if_then_else(
         type.lifetime.equals("AVA_CALL").if_then_else(
             f"{size} += command_channel_buffer_size(__chan, {size_expr});\n",
             f"{size} += ava_shadow_buffer_size(&__ava_endpoint, __chan, {size_expr});\n"
         ),
         type.lifetime.equals("AVA_CALL").if_then_else(
             "",
             f"{size} += ava_shadow_buffer_size_without_data(&__ava_endpoint, __chan, {size_expr});\n"
         ))
예제 #2
0
파일: buffer_handling.py 프로젝트: yuhc/ava
def get_buffer(
    target: str,
    target_type: Type,
    value: str,
    type_: Type,
    *,
    original_type: Optional[Type],
    precomputed_size=None,
    not_null=False,
    declare_buffer_size=True,
) -> Expr:
    """
    Generate code that sets target to the local buffer to use for value.
    After this code executes `__buffer_size` is equal to the buffer size in elements.
    :param target: The variable in which to store the buffer pointer.
    :param value: The original value to translate.
    :param type_: The type of value.
    :param original_type: The original type if type is immediately inside a ConditionalType.
    :param precomputed_size: The expression for a precomputed size of value in *elements*.
    :param not_null: If True, then this function does not generate NULL checks.
    :return: A series of C statements.
    """
    size_expr = compute_buffer_size(
        type_, original_type) if precomputed_size is None else precomputed_size
    declarations = DECLARE_BUFFER_SIZE_EXPR if declare_buffer_size else Expr(
        "")

    pointee_size = f"sizeof({type_.pointee.spelling})"
    # for void* buffer, assume that each element is 1 byte
    if type_.pointee.is_void:
        pointee_size = "1"

    return declarations.then((
        type_.lifetime.not_equals("AVA_CALL") &
        (Expr(value).not_equals("NULL") | not_null)
    ).if_then_else(
        # FIXME: The initial assert is probably incorrect. Should it be checking the ADDRESSES?
        #   Should it be there at all? Commented for now: AVA_DEBUG_ASSERT({target} != {value});
        #   (was at top of code)
        # FIXME: Should we check the buffer size? Can it be computed here?
        #   AVA_DEBUG_ASSERT(__buffer_size == {size_expr}); (was at bottom of code)
        f"""
            /* Size is in bytes until the division below. */
            {target} = ({target_type})({get_buffer_expr(value, type_, not_null=not_null, size_out="__buffer_size")});
            AVA_DEBUG_ASSERT(__buffer_size % {pointee_size} == 0);
            __buffer_size /= {pointee_size};
            /* Size is now in elements. */
        """.lstrip(),
        f"""
            __buffer_size = {size_expr};
            {target} = ({target_type})({get_buffer_expr(value, type_, not_null=not_null, size_out="__buffer_size")});
        """.strip(),
    ))
예제 #3
0
def attach_buffer(target,
                  value,
                  data,
                  type: Type,
                  copy: Union[Expr, Any],
                  *,
                  cmd,
                  original_type: Optional[Type],
                  expect_reply: bool,
                  precomputed_size=None):
    """
    Generate code to attach a buffer to a command.

    :param target: The value to set to the buffer offset after attaching.
    :param value: The value to attach.
    :param type: The type of value.
    :param copy: An expression which is true if if this value should be copied.
    :param cmd: The command to attach to.
    :param original_type: The original type if type is immediately inside a ConditionalType.
    :param precomputed_size: The expression for a precomputed size of value in *elements*.
    :return: A series of C statements.
    """
    cmd = f"(struct command_base*){cmd}"
    size_expr = size_to_bytes(
        compute_buffer_size(type, original_type)
        if precomputed_size is None else precomputed_size, type)

    def simple_attach(func):
        return lambda: f"""{target} = ({type.nonconst.spelling}){func}(__chan, {cmd}, {data}, {size_expr});
                        """

    def zerocopy_attach(func="ava_zcopy_region_encode_position_independent"):
        return lambda: f"""{target} = ({type.nonconst.spelling}){func}(__ava_endpoint.zcopy_region, {data});
                        """

    def shadow_attach(func):
        return lambda: f"""{target} = ({type.nonconst.spelling}){func}(&__ava_endpoint,
                        __chan, {cmd}, {value}, {data}, {size_expr},
                        {type.lifetime}, {type.buffer_allocator}, {type.buffer_deallocator},
                        alloca(sizeof(struct ava_buffer_header_t)));"""

    return type.transfer.equals("NW_ZEROCOPY_BUFFER").if_then_else(
        zerocopy_attach(),
        type.lifetime.equals("AVA_CALL").if_then_else(
            Expr(copy).if_then_else(
                simple_attach("command_channel_attach_buffer"),
                f"{target} = HAS_OUT_BUFFER_SENTINEL;"
                if expect_reply else f"{target} = NULL; /* No output */\n"),
            Expr(copy).if_then_else(
                shadow_attach("ava_shadow_buffer_attach_buffer"),
                shadow_attach("ava_shadow_buffer_attach_buffer_without_data"),
            )))