Example #1
0
def _call_make_placeholder(stmt_expr, context, sig):
    if sig.output_type is None:
        return 0, 0, 0

    output_placeholder = context.new_placeholder(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32

    if isinstance(sig.output_type, BaseType):
        returner = output_placeholder
    elif isinstance(sig.output_type, ByteArrayLike):
        returner = output_placeholder
    elif isinstance(sig.output_type, TupleLike):
        # incase of struct we need to decode the output and then return it
        returner = ["seq"]
        decoded_placeholder = context.new_placeholder(typ=sig.output_type)
        decoded_node = LLLnode(decoded_placeholder,
                               typ=sig.output_type,
                               location="memory")
        output_node = LLLnode(output_placeholder,
                              typ=sig.output_type,
                              location="memory")
        returner.append(abi_decode(decoded_node, output_node))
        returner.extend([decoded_placeholder])
    elif isinstance(sig.output_type, ListType):
        returner = output_placeholder
    else:
        raise TypeCheckFailure(f"Invalid output type: {sig.output_type}")
    return output_placeholder, returner, output_size
Example #2
0
def get_external_call_output(sig, context):
    if not sig.output_type:
        return 0, 0, []
    output_placeholder = context.new_internal_variable(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32
    if isinstance(sig.output_type, BaseType):
        returner = [0, output_placeholder]
    elif isinstance(sig.output_type, ByteArrayLike):
        returner = [0, output_placeholder + 32]
    elif isinstance(sig.output_type, TupleLike):
        # incase of struct we need to decode the output and then return it
        returner = ["seq"]
        decoded_placeholder = context.new_internal_variable(
            typ=sig.output_type)
        decoded_node = LLLnode(decoded_placeholder,
                               typ=sig.output_type,
                               location="memory")
        output_node = LLLnode(output_placeholder,
                              typ=sig.output_type,
                              location="memory")
        returner.append(abi_decode(decoded_node, output_node))
        returner.extend([0, decoded_placeholder])
    elif isinstance(sig.output_type, ListType):
        returner = [0, output_placeholder]
    else:
        raise TypeCheckFailure(f"Invalid output type: {sig.output_type}")
    return output_placeholder, output_size, returner
Example #3
0
def base_type_conversion(orig, frm, to, pos):
    orig = unwrap_location(orig)
    if getattr(frm, 'is_literal', False) and frm.typ in ('int128', 'uint256') and not SizeLimits.in_bounds(frm.typ, orig.value):
        raise InvalidLiteralException("Number out of range: " + str(orig.value), pos)
    # # Valid bytes[32] to bytes32 assignment.
    # if isinstance(to, BaseType) and to.typ = 'bytes32' and isinstance(frm, ByteArrayType) and frm.maxlen == 32:
    #     return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    if not isinstance(frm, (BaseType, NullType)) or not isinstance(to, BaseType):
        raise TypeMismatchException("Base type conversion from or to non-base type: %r %r" % (frm, to), pos)
    elif is_base_type(frm, to.typ) and are_units_compatible(frm, to):
        return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    elif is_base_type(frm, 'int128') and is_base_type(to, 'decimal') and are_units_compatible(frm, to):
        return LLLnode.from_list(['mul', orig, DECIMAL_DIVISOR], typ=BaseType('decimal', to.unit, to.positional))
    elif isinstance(frm, NullType):
        if to.typ not in ('int128', 'bool', 'uint256', 'address', 'bytes32', 'decimal'):
            # This is only to future proof the use of  base_type_conversion.
            raise TypeMismatchException("Cannot convert null-type object to type %r" % to, pos)  # pragma: no cover
        return LLLnode.from_list(0, typ=to)
    elif isinstance(to, ContractType) and frm.typ == 'address':
        return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    # Integer literal conversion.
    elif (frm.typ, to.typ, frm.is_literal) == ('int128', 'uint256', True):
        return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    else:
        raise TypeMismatchException("Typecasting from base type %r to %r unavailable" % (frm, to), pos)
Example #4
0
def base_type_conversion(orig, frm, to, pos, in_function_call=False):
    orig = unwrap_location(orig)
    if getattr(frm, 'is_literal', False) and frm.typ in ('int128', 'uint256'):
        if not SizeLimits.in_bounds(frm.typ, orig.value):
            raise InvalidLiteralException("Number out of range: " + str(orig.value), pos)
        # Special Case: Literals in function calls should always convey unit type as well.
        if in_function_call and not (frm.unit == to.unit and frm.positional == to.positional):
            raise InvalidLiteralException("Function calls require explicit unit definitions on calls, expected %r" % to, pos)
    if not isinstance(frm, (BaseType, NullType)) or not isinstance(to, BaseType):
        raise TypeMismatchException("Base type conversion from or to non-base type: %r %r" % (frm, to), pos)
    elif is_base_type(frm, to.typ) and are_units_compatible(frm, to):
        return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    elif is_base_type(frm, 'int128') and is_base_type(to, 'decimal') and are_units_compatible(frm, to):
        return LLLnode.from_list(['mul', orig, DECIMAL_DIVISOR], typ=BaseType('decimal', to.unit, to.positional))
    elif isinstance(frm, NullType):
        if to.typ not in ('int128', 'bool', 'uint256', 'address', 'bytes32', 'decimal'):
            # This is only to future proof the use of  base_type_conversion.
            raise TypeMismatchException("Cannot convert null-type object to type %r" % to, pos)  # pragma: no cover
        return LLLnode.from_list(0, typ=to)
    elif isinstance(to, ContractType) and frm.typ == 'address':
        return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    # Integer literal conversion.
    elif (frm.typ, to.typ, frm.is_literal) == ('int128', 'uint256', True):
        return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
    else:
        raise TypeMismatchException("Typecasting from base type %r to %r unavailable" % (frm, to), pos)
Example #5
0
def gen_tuple_return(stmt, context, sub):
    abi_typ = abi_type_of(context.return_type)
    # according to the ABI, return types are ALWAYS tuples even if
    # only one element is being returned.
    # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding
    # "and the return values v_1, ..., v_k of f are encoded as
    #
    #    enc((v_1, ..., v_k))
    #    i.e. the values are combined into a tuple and encoded.
    # "
    # therefore, wrap it in a tuple if it's not already a tuple.
    # (big difference between returning `(bytes,)` and `bytes`.
    abi_typ = ensure_tuple(abi_typ)
    abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound()
    dst, _ = context.memory_allocator.increase_memory(abi_bytes_needed)
    return_buffer = LLLnode(dst,
                            location="memory",
                            annotation="return_buffer",
                            typ=context.return_type)

    check_assign(return_buffer, sub, pos=getpos(stmt))

    # in case of multi we can't create a variable to store location of the return expression
    # as multi can have data from multiple location like store, calldata etc
    if sub.value == "multi":
        encode_out = abi_encode(return_buffer,
                                sub,
                                pos=getpos(stmt),
                                returns=True)
        load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
        os = [
            "seq",
            ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
            make_return_stmt(stmt, context, return_buffer, load_return_len),
        ]
        return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)

    # for all othe cases we are creating a stack variable named sub_loc to store the  location
    # of the return expression. This is done so that the return expression does not get evaluated
    # abi-encode uses a function named o_list which evaluate the expression multiple times
    sub_loc = LLLnode("sub_loc", typ=sub.typ, location=sub.location)
    encode_out = abi_encode(return_buffer,
                            sub_loc,
                            pos=getpos(stmt),
                            returns=True)
    load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
    os = [
        "with",
        "sub_loc",
        sub,
        [
            "seq",
            ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
            make_return_stmt(stmt, context, return_buffer, load_return_len),
        ],
    ]
    return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
Example #6
0
def abi_decode(lll_node, src, pos=None):
    os = o_list(lll_node, pos=pos)
    lll_ret = ["seq"]
    parent_abi_t = abi_type_of(lll_node.typ)
    for i, o in enumerate(os):
        abi_t = abi_type_of(o.typ)
        src_loc = LLLnode("src_loc", typ=o.typ, location=src.location)
        if parent_abi_t.is_tuple():
            if abi_t.is_dynamic():
                child_loc = ["add", "src", unwrap_location(src_loc)]
                child_loc = LLLnode.from_list(child_loc,
                                              typ=o.typ,
                                              location=src.location)
            else:
                child_loc = src_loc
            # descend into the child tuple
            lll_ret.append(abi_decode(o, child_loc, pos=pos))
        else:
            lll_ret.append(
                make_setter(o, src_loc, location=o.location, pos=pos))

        if i + 1 == len(os):
            pass  # optimize out the last pointer increment
        else:
            sz = abi_t.embedded_static_size()
            lll_ret.append(["set", "src_loc", ["add", "src_loc", sz]])

    lll_ret = ["with", "src", src, ["with", "src_loc", "src", lll_ret]]

    return lll_ret
Example #7
0
def abi_decode(lll_node, src, pos=None):
    os = o_list(lll_node, pos=pos)
    lll_ret = []
    src_ptr = 'src'  # pointer to beginning of buffer
    src_loc = 'src_loc'  # pointer to read location in static section
    parent_abi_t = abi_type_of(src.typ)
    for i, o in enumerate(os):
        abi_t = abi_type_of(o.typ)
        src_loc = LLLnode('src_loc', typ=o.typ, location=src.location)
        if parent_abi_t.is_tuple():
            if abi_t.is_dynamic():
                child_loc = ['add', src_ptr, unwrap_location(src_loc)]
            else:
                child_loc = src_loc
            # descend into the child tuple
            lll_ret.append(abi_decode(o, child_loc, pos=pos))
        else:
            lll_ret.append(make_setter(o, src_loc))

        if i + 1 == len(os):
            pass  # optimize out the last pointer increment
        else:
            sz = abi_t.embedded_static_size()
            lll_ret.append(['set', src_loc, ['add', src_loc, sz]])

    lll_ret = [
        'with', 'src', src, ['with', 'src_loc', 'src', ['seq', lll_ret]]
    ]

    return lll_ret
Example #8
0
def base_type_conversion(orig, frm, to, pos, in_function_call=False):
    orig = unwrap_location(orig)

    # do the base type check so we can use BaseType attributes
    if not isinstance(frm, BaseType) or not isinstance(to, BaseType):
        return

    if getattr(frm, "is_literal", False):
        for typ in (frm.typ, to.typ):
            if typ in ("int128", "uint256") and not SizeLimits.in_bounds(typ, orig.value):
                return

    is_decimal_int128_conversion = frm.typ == "int128" and to.typ == "decimal"
    is_same_type = frm.typ == to.typ
    is_literal_conversion = frm.is_literal and (frm.typ, to.typ) == ("int128", "uint256")
    is_address_conversion = isinstance(frm, InterfaceType) and to.typ == "address"
    if not (
        is_same_type
        or is_literal_conversion
        or is_address_conversion
        or is_decimal_int128_conversion
    ):
        return

    # handle None value inserted by `empty()`
    if orig.value is None:
        return LLLnode.from_list(0, typ=to)

    if is_decimal_int128_conversion:
        return LLLnode.from_list(["mul", orig, DECIMAL_DIVISOR], typ=BaseType("decimal"),)

    return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
Example #9
0
def gen_tuple_return(stmt, context, sub):
    # Is from a call expression.
    if sub.args and len(sub.args[0].args) > 0 and (
            sub.args[0].args[0].value == "call"
            or sub.args[0].args[0].value == "staticcall"):
        # self-call to external.
        mem_pos = sub
        mem_size = get_size_of_type(sub.typ) * 32
        return LLLnode.from_list(["return", mem_pos, mem_size], typ=sub.typ)

    elif sub.annotation and "Internal Call" in sub.annotation:
        mem_pos = sub.args[
            -1].value if sub.value == "seq_unchecked" else sub.args[0].args[-1]
        mem_size = get_size_of_type(sub.typ) * 32
        # Add zero padder if bytes are present in output.
        zero_padder = ["pass"]
        byte_arrays = [(i, x) for i, x in enumerate(sub.typ.tuple_members())
                       if isinstance(x, ByteArrayLike)]
        if byte_arrays:
            i, x = byte_arrays[-1]
            zero_padder = zero_pad(bytez_placeholder=[
                "add", mem_pos, ["mload", mem_pos + i * 32]
            ])
        return LLLnode.from_list(
            ["seq"] + [sub] + [zero_padder] +
            [make_return_stmt(stmt, context, mem_pos, mem_size)],
            typ=sub.typ,
            pos=getpos(stmt),
            valency=0,
        )

    abi_typ = abi_type_of(context.return_type)
    # according to the ABI, return types are ALWAYS tuples even if
    # only one element is being returned.
    # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding
    # "and the return values v_1, ..., v_k of f are encoded as
    #
    #    enc((v_1, ..., v_k))
    #    i.e. the values are combined into a tuple and encoded.
    # "
    # therefore, wrap it in a tuple if it's not already a tuple.
    # (big difference between returning `(bytes,)` and `bytes`.
    abi_typ = ensure_tuple(abi_typ)
    abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound()
    dst, _ = context.memory_allocator.increase_memory(abi_bytes_needed)
    return_buffer = LLLnode(dst,
                            location="memory",
                            annotation="return_buffer",
                            typ=context.return_type)

    check_assign(return_buffer, sub, pos=getpos(stmt))

    encode_out = abi_encode(return_buffer, sub, pos=getpos(stmt), returns=True)
    load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
    os = [
        "seq",
        ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
        make_return_stmt(stmt, context, return_buffer, load_return_len),
    ]
    return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
Example #10
0
def base_type_conversion(orig, frm, to, pos, in_function_call=False):
    orig = unwrap_location(orig)

    # do the base type check so we can use BaseType attributes
    if not isinstance(frm, BaseType) or not isinstance(to, BaseType):
        raise TypeMismatch(
            f"Base type conversion from or to non-base type: {frm} {to}", pos)

    if getattr(frm, 'is_literal', False):
        if frm.typ in ('int128', 'uint256'):
            if not SizeLimits.in_bounds(frm.typ, orig.value):
                raise InvalidLiteral(f"Number out of range: {orig.value}", pos)

        if to.typ in ('int128', 'uint256'):
            if not SizeLimits.in_bounds(to.typ, orig.value):
                raise InvalidLiteral(f"Number out of range: {orig.value}", pos)

    is_decimal_int128_conversion = frm.typ == 'int128' and to.typ == 'decimal'
    is_same_type = frm.typ == to.typ
    is_literal_conversion = frm.is_literal and (frm.typ, to.typ) == ('int128',
                                                                     'uint256')
    is_address_conversion = isinstance(frm,
                                       ContractType) and to.typ == 'address'
    if not (is_same_type or is_literal_conversion or is_address_conversion
            or is_decimal_int128_conversion):
        raise TypeMismatch(
            f"Typecasting from base type {frm} to {to} unavailable", pos)

    # handle None value inserted by `empty()`
    if orig.value is None:
        return LLLnode.from_list(0, typ=to)

    if is_decimal_int128_conversion:
        return LLLnode.from_list(
            ['mul', orig, DECIMAL_DIVISOR],
            typ=BaseType('decimal'),
        )

    return LLLnode(orig.value,
                   orig.args,
                   typ=to,
                   add_gas_estimate=orig.add_gas_estimate)
Example #11
0
def gen_tuple_return(stmt, context, sub):
    abi_typ = abi_type_of(context.return_type)
    # according to the ABI, return types are ALWAYS tuples even if
    # only one element is being returned.
    # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding
    # "and the return values v_1, ..., v_k of f are encoded as
    #
    #    enc((v_1, ..., v_k))
    #    i.e. the values are combined into a tuple and encoded.
    # "
    # therefore, wrap it in a tuple if it's not already a tuple.
    # (big difference between returning `(bytes,)` and `bytes`.
    abi_typ = ensure_tuple(abi_typ)
    abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound()
    dst = context.memory_allocator.expand_memory(abi_bytes_needed)
    return_buffer = LLLnode(dst,
                            location="memory",
                            annotation="return_buffer",
                            typ=context.return_type)

    check_assign(return_buffer, sub, pos=getpos(stmt))

    if sub.value == "multi":

        if isinstance(context.return_type,
                      TupleType) and not abi_typ.dynamic_size_bound():
            # for tuples where every value is of the same type and a fixed length,
            # we can simplify the encoding by treating it as though it were an array
            base_types = set()
            for typ in context.return_type.members:
                while isinstance(typ, ListType):
                    typ = typ.subtype
                base_types.add(typ.typ)

            if len(base_types) == 1:
                new_sub = LLLnode.from_list(
                    context.new_internal_variable(context.return_type),
                    typ=context.return_type,
                    location="memory",
                )
                setter = make_setter(new_sub, sub, "memory", pos=getpos(stmt))
                return LLLnode.from_list(
                    [
                        "seq",
                        setter,
                        make_return_stmt(
                            stmt,
                            context,
                            new_sub,
                            get_size_of_type(context.return_type) * 32,
                        ),
                    ],
                    typ=None,
                    pos=getpos(stmt),
                )

        # in case of multi we can't create a variable to store location of the return expression
        # as multi can have data from multiple location like store, calldata etc
        encode_out = abi_encode(return_buffer,
                                sub,
                                pos=getpos(stmt),
                                returns=True)
        load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
        os = [
            "seq",
            ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
            make_return_stmt(stmt, context, return_buffer, load_return_len),
        ]
        return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)

    # for tuple return types where a function is called inside the tuple, we
    # process the calls prior to encoding the return data
    if sub.value == "seq_unchecked" and sub.args[-1].value == "multi":
        encode_out = abi_encode(return_buffer,
                                sub.args[-1],
                                pos=getpos(stmt),
                                returns=True)
        load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
        os = (["seq"] + sub.args[:-1] + [
            ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
            make_return_stmt(stmt, context, return_buffer, load_return_len),
        ])
        return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)

    # for all othe cases we are creating a stack variable named sub_loc to store the  location
    # of the return expression. This is done so that the return expression does not get evaluated
    # abi-encode uses a function named o_list which evaluate the expression multiple times
    sub_loc = LLLnode("sub_loc", typ=sub.typ, location=sub.location)
    encode_out = abi_encode(return_buffer,
                            sub_loc,
                            pos=getpos(stmt),
                            returns=True)
    load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
    os = [
        "with",
        "sub_loc",
        sub,
        [
            "seq",
            ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
            make_return_stmt(stmt, context, return_buffer, load_return_len),
        ],
    ]
    return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
Example #12
0
def gen_tuple_return(stmt, context, sub):
    # Is from a call expression.
    if sub.args and len(
            sub.args[0].args) > 0 and sub.args[0].args[0].value == 'call':
        # self-call to public.
        mem_pos = sub.args[0].args[-1]
        mem_size = get_size_of_type(sub.typ) * 32
        return LLLnode.from_list(['return', mem_pos, mem_size], typ=sub.typ)

    elif (sub.annotation and 'Internal Call' in sub.annotation):
        mem_pos = sub.args[
            -1].value if sub.value == 'seq_unchecked' else sub.args[0].args[-1]
        mem_size = get_size_of_type(sub.typ) * 32
        # Add zero padder if bytes are present in output.
        zero_padder = ['pass']
        byte_arrays = [(i, x) for i, x in enumerate(sub.typ.tuple_members())
                       if isinstance(x, ByteArrayLike)]
        if byte_arrays:
            i, x = byte_arrays[-1]
            zero_padder = zero_pad(bytez_placeholder=[
                'add', mem_pos, ['mload', mem_pos + i * 32]
            ],
                                   maxlen=x.maxlen,
                                   context=context)
        return LLLnode.from_list(
            ['seq'] + [sub] + [zero_padder] +
            [make_return_stmt(stmt, context, mem_pos, mem_size)],
            typ=sub.typ,
            pos=getpos(stmt),
            valency=0)

    subs = []
    # Pre-allocate loop_memory_position if required for private function returning.
    loop_memory_position = (context.new_placeholder(
        typ=BaseType('uint256')) if context.is_private else None)
    # Allocate dynamic off set counter, to keep track of the total packed dynamic data size.
    dynamic_offset_counter_placeholder = context.new_placeholder(
        typ=BaseType('uint256'))
    dynamic_offset_counter = LLLnode(
        dynamic_offset_counter_placeholder,
        typ=None,
        annotation="dynamic_offset_counter"  # dynamic offset position counter.
    )
    new_sub = LLLnode.from_list(
        context.new_placeholder(typ=BaseType('uint256')),
        typ=context.return_type,
        location='memory',
        annotation='new_sub',
    )
    left_token = LLLnode.from_list('_loc', typ=new_sub.typ, location="memory")

    def get_dynamic_offset_value():
        # Get value of dynamic offset counter.
        return ['mload', dynamic_offset_counter]

    def increment_dynamic_offset(dynamic_spot):
        # Increment dyanmic offset counter in memory.
        return [
            'mstore', dynamic_offset_counter,
            [
                'add', ['add', ['ceil32', ['mload', dynamic_spot]], 32],
                ['mload', dynamic_offset_counter]
            ]
        ]

    if not isinstance(context.return_type, TupleLike):
        raise TypeMismatchException(
            'Trying to return %r when expecting %r' %
            (sub.typ, context.return_type), getpos(stmt))
    items = context.return_type.tuple_items()

    dynamic_offset_start = 32 * len(items)  # The static list of args end.

    for i, (key, typ) in enumerate(items):
        variable_offset = LLLnode.from_list(
            ['add', 32 * i, left_token],
            typ=typ,
            annotation='variable_offset',
        )  # variable offset of destination
        if sub.typ.is_literal:
            arg = sub.args[i]
        else:
            arg = add_variable_offset(parent=sub, key=key, pos=getpos(stmt))

        if isinstance(typ, ByteArrayLike):
            # Store offset pointer value.
            subs.append(
                ['mstore', variable_offset,
                 get_dynamic_offset_value()])

            # Store dynamic data, from offset pointer onwards.
            dynamic_spot = LLLnode.from_list(
                ['add', left_token,
                 get_dynamic_offset_value()],
                location="memory",
                typ=typ,
                annotation='dynamic_spot',
            )
            subs.append(
                make_setter(dynamic_spot,
                            arg,
                            location="memory",
                            pos=getpos(stmt)))
            subs.append(increment_dynamic_offset(dynamic_spot))

        elif isinstance(typ, BaseType):
            subs.append(
                make_setter(variable_offset, arg, "memory", pos=getpos(stmt)))
        elif isinstance(typ, TupleLike):
            subs.append(gen_tuple_return(stmt, context, arg))
        else:
            # Maybe this should panic because the type error should be
            # caught at an earlier type-checking stage.
            raise TypeMismatchException(
                "Can't return type %s as part of tuple" % arg.typ, stmt)

    setter = LLLnode.from_list([
        'seq', ['mstore', dynamic_offset_counter, dynamic_offset_start],
        ['with', '_loc', new_sub, ['seq'] + subs]
    ],
                               typ=None)

    return LLLnode.from_list([
        'seq', setter,
        make_return_stmt(stmt, context, new_sub, get_dynamic_offset_value(),
                         loop_memory_position)
    ],
                             typ=None,
                             pos=getpos(stmt),
                             valency=0)
Example #13
0
def _add_ofst(loc, ofst):
    if isinstance(loc.value, int):
        return LLLnode(loc.value + ofst)
    return ["add", loc, ofst]
Example #14
0
def abi_encode(dst, lll_node, pos=None, bufsz=None, returns=False):
    parent_abi_t = abi_type_of(lll_node.typ)
    size_bound = parent_abi_t.static_size() + parent_abi_t.dynamic_size_bound()
    if bufsz is not None and bufsz < 32 * size_bound:
        raise CompilerPanic("buffer provided to abi_encode not large enough")

    lll_ret = ["seq"]
    dyn_ofst = "dyn_ofst"  # current offset in the dynamic section
    dst_begin = "dst"  # pointer to beginning of buffer
    dst_loc = "dst_loc"  # pointer to write location in static section
    os = o_list(lll_node, pos=pos)

    for i, o in enumerate(os):
        abi_t = abi_type_of(o.typ)

        if parent_abi_t.is_tuple():
            if abi_t.is_dynamic():
                lll_ret.append(["mstore", dst_loc, dyn_ofst])
                # recurse
                child_dst = ["add", dst_begin, dyn_ofst]
                child = abi_encode(child_dst, o, pos=pos, returns=True)
                # increment dyn ofst for the return
                # (optimization note:
                #   if non-returning and this is the last dyn member in
                #   the tuple, this set can be elided.)
                lll_ret.append(["set", dyn_ofst, ["add", dyn_ofst, child]])
            else:
                # recurse
                lll_ret.append(abi_encode(dst_loc, o, pos=pos, returns=False))

        elif isinstance(o.typ, BaseType):
            d = LLLnode(dst_loc, typ=o.typ, location="memory")
            lll_ret.append(make_setter(d, o, location=d.location, pos=pos))
        elif isinstance(o.typ, ByteArrayLike):
            d = LLLnode.from_list(dst_loc, typ=o.typ, location="memory")
            lll_ret.append([
                "seq",
                make_setter(d, o, location=d.location, pos=pos),
                zero_pad(d)
            ])
        else:
            raise CompilerPanic(f"unreachable type: {o.typ}")

        if i + 1 == len(os):
            pass  # optimize out the last increment to dst_loc
        else:  # note: always false for non-tuple types
            sz = abi_t.embedded_static_size()
            lll_ret.append(["set", dst_loc, ["add", dst_loc, sz]])

    # declare LLL variables.
    if returns:
        if not parent_abi_t.is_dynamic():
            lll_ret.append(parent_abi_t.embedded_static_size())
        elif parent_abi_t.is_tuple():
            lll_ret.append("dyn_ofst")
        elif isinstance(lll_node.typ, ByteArrayLike):
            # for abi purposes, return zero-padded length
            calc_len = ["ceil32", ["add", 32, ["mload", dst_loc]]]
            lll_ret.append(calc_len)
        else:
            raise CompilerPanic("unknown type {lll_node.typ}")

    if not (parent_abi_t.is_dynamic() and parent_abi_t.is_tuple()):
        pass  # optimize out dyn_ofst allocation if we don't need it
    else:
        dyn_section_start = parent_abi_t.static_size()
        lll_ret = ["with", "dyn_ofst", dyn_section_start, lll_ret]

    lll_ret = ["with", dst_begin, dst, ["with", dst_loc, dst_begin, lll_ret]]

    return LLLnode.from_list(lll_ret)
Example #15
0
    def call(self):
        from vyper.functions import (
            dispatch_table, )

        if isinstance(self.expr.func, ast.Name):
            function_name = self.expr.func.id

            if function_name in dispatch_table:
                return dispatch_table[function_name](self.expr, self.context)

            # Struct constructors do not need `self` prefix.
            elif function_name in self.context.structs:
                if not self.context.in_assignment:
                    raise StructureException(
                        "Struct constructor must be called in RHS of assignment.",
                        self.expr)
                args = self.expr.args
                if len(args) != 1:
                    raise StructureException(
                        "Struct constructor is called with one argument only",
                        self.expr)

                arg = args[0]
                if not isinstance(arg, ast.Dict):
                    raise TypeMismatchException(
                        "Struct can only be constructed with a dict",
                        self.expr)
                sub = Expr.struct_literals(arg, self.context)
                if sub.typ.name is not None:
                    raise TypeMismatchException(
                        "Struct can only be constructed with a dict",
                        self.expr)

                typ = StructType(sub.typ.members, function_name)

                # OR:
                # sub.typ = typ
                # return sub
                return LLLnode(sub.value,
                               typ=typ,
                               args=sub.args,
                               location=sub.location,
                               pos=getpos(self.expr),
                               add_gas_estimate=sub.add_gas_estimate,
                               valency=sub.valency,
                               annotation=function_name)

            else:
                err_msg = "Not a top-level function: {}".format(function_name)
                if function_name in [
                        x.split('(')[0]
                        for x, _ in self.context.sigs['self'].items()
                ]:
                    err_msg += ". Did you mean self.{}?".format(function_name)
                raise StructureException(err_msg, self.expr)
        elif isinstance(self.expr.func, ast.Attribute) and isinstance(
                self.expr.func.value,
                ast.Name) and self.expr.func.value.id == "self":
            return self_call.make_call(self.expr, self.context)
        else:
            return external_call.make_external_call(self.expr, self.context)