Beispiel #1
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)
Beispiel #2
0
def pack_args_by_32(holder,
                    maxlen,
                    arg,
                    typ,
                    context,
                    placeholder,
                    dynamic_offset_counter=None,
                    datamem_start=None,
                    zero_pad_i=None,
                    pos=None):
    """
    Copy necessary variables to pre-allocated memory section.

    :param holder: Complete holder for all args
    :param maxlen: Total length in bytes of the full arg section (static + dynamic).
    :param arg: Current arg to pack
    :param context: Context of arg
    :param placeholder: Static placeholder for static argument part.
    :param dynamic_offset_counter: position counter stored in static args.
    :param dynamic_placeholder: pointer to current position in memory to write dynamic values to.
    :param datamem_start: position where the whole datemem section starts.
    """

    if isinstance(typ, BaseType):
        if isinstance(arg, LLLnode):
            value = unwrap_location(arg)
        else:
            value = Expr(arg, context).lll_node
            value = base_type_conversion(value, value.typ, typ, pos)
        holder.append(
            LLLnode.from_list(['mstore', placeholder, value],
                              typ=typ,
                              location='memory'))
    elif isinstance(typ, ByteArrayLike):

        if isinstance(arg, LLLnode):  # Is prealloacted variable.
            source_lll = arg
        else:
            source_lll = Expr(arg, context).lll_node

        # Set static offset, in arg slot.
        holder.append(
            LLLnode.from_list(
                ['mstore', placeholder, ['mload', dynamic_offset_counter]]))
        # Get the biginning to write the ByteArray to.
        dest_placeholder = LLLnode.from_list(
            ['add', datamem_start, ['mload', dynamic_offset_counter]],
            typ=typ,
            location='memory',
            annotation="pack_args_by_32:dest_placeholder")
        copier = make_byte_array_copier(dest_placeholder, source_lll, pos=pos)
        holder.append(copier)
        # Add zero padding.
        holder.append(zero_pad(dest_placeholder, maxlen,
                               zero_pad_i=zero_pad_i))

        # Increment offset counter.
        increment_counter = LLLnode.from_list(
            [
                'mstore',
                dynamic_offset_counter,
                [
                    'add',
                    [
                        'add', ['mload', dynamic_offset_counter],
                        ['ceil32', ['mload', dest_placeholder]]
                    ],
                    32,
                ],
            ],
            annotation='Increment dynamic offset counter')
        holder.append(increment_counter)
    elif isinstance(typ, ListType):
        maxlen += (typ.count - 1) * 32
        typ = typ.subtype

        def check_list_type_match(provided):  # Check list types match.
            if provided != typ:
                raise TypeMismatchException(
                    "Log list type '%s' does not match provided, expected '%s'"
                    % (provided, typ))

        # NOTE: Below code could be refactored into iterators/getter functions for each type of
        #       repetitive loop. But seeing how each one is a unique for loop, and in which way
        #       the sub value makes the difference in each type of list clearer.

        # List from storage
        if isinstance(arg, ast.Attribute) and arg.value.id == 'self':
            stor_list = context.globals[arg.attr]
            check_list_type_match(stor_list.typ.subtype)
            size = stor_list.typ.count
            mem_offset = 0
            for i in range(0, size):
                storage_offset = i
                arg2 = LLLnode.from_list(
                    [
                        'sload',
                        [
                            'add', ['sha3_32',
                                    Expr(arg, context).lll_node],
                            storage_offset
                        ]
                    ],
                    typ=typ,
                )
                holder, maxlen = pack_args_by_32(
                    holder,
                    maxlen,
                    arg2,
                    typ,
                    context,
                    placeholder + mem_offset,
                    pos=pos,
                )
                mem_offset += get_size_of_type(typ) * 32

        # List from variable.
        elif isinstance(arg, ast.Name):
            size = context.vars[arg.id].size
            pos = context.vars[arg.id].pos
            check_list_type_match(context.vars[arg.id].typ.subtype)
            mem_offset = 0
            for _ in range(0, size):
                arg2 = LLLnode.from_list(
                    pos + mem_offset,
                    typ=typ,
                    location=context.vars[arg.id].location)
                holder, maxlen = pack_args_by_32(
                    holder,
                    maxlen,
                    arg2,
                    typ,
                    context,
                    placeholder + mem_offset,
                    pos=pos,
                )
                mem_offset += get_size_of_type(typ) * 32

        # List from list literal.
        else:
            mem_offset = 0
            for arg2 in arg.elts:
                holder, maxlen = pack_args_by_32(
                    holder,
                    maxlen,
                    arg2,
                    typ,
                    context,
                    placeholder + mem_offset,
                    pos=pos,
                )
                mem_offset += get_size_of_type(typ) * 32
    return holder, maxlen
Beispiel #3
0
    def parse_return(self):
        if self.context.return_type is None:
            if self.stmt.value:
                raise TypeMismatchException("Not expecting to return a value",
                                            self.stmt)
            return LLLnode.from_list(
                make_return_stmt(self.stmt, self.context, 0, 0),
                typ=None,
                pos=getpos(self.stmt),
                valency=0,
            )
        if not self.stmt.value:
            raise TypeMismatchException("Expecting to return a value",
                                        self.stmt)

        sub = Expr(self.stmt.value, self.context).lll_node

        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            sub = unwrap_location(sub)

            if not isinstance(self.context.return_type, BaseType):
                raise TypeMismatchException(
                    f"Return type units mismatch {sub.typ} {self.context.return_type}",
                    self.stmt.value)
            elif self.context.return_type != sub.typ and not sub.typ.is_literal:
                raise TypeMismatchException(
                    f"Trying to return base type {sub.typ}, output expecting "
                    f"{self.context.return_type}",
                    self.stmt.value,
                )
            elif sub.typ.is_literal and (
                    self.context.return_type.typ == sub.typ
                    or 'int' in self.context.return_type.typ
                    and 'int' in sub.typ.typ):  # noqa: E501
                if not SizeLimits.in_bounds(self.context.return_type.typ,
                                            sub.value):
                    raise InvalidLiteralException(
                        "Number out of range: " + str(sub.value), self.stmt)
                else:
                    return LLLnode.from_list(
                        [
                            'seq', ['mstore', 0, sub],
                            make_return_stmt(self.stmt, self.context, 0, 32)
                        ],
                        typ=None,
                        pos=getpos(self.stmt),
                        valency=0,
                    )
            elif is_base_type(sub.typ, self.context.return_type.typ) or (
                    is_base_type(sub.typ, 'int128') and is_base_type(
                        self.context.return_type, 'int256')):  # noqa: E501
                return LLLnode.from_list(
                    [
                        'seq', ['mstore', 0, sub],
                        make_return_stmt(self.stmt, self.context, 0, 32)
                    ],
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                raise TypeMismatchException(
                    f"Unsupported type conversion: {sub.typ} to {self.context.return_type}",
                    self.stmt.value,
                )
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayLike):
            if not sub.typ.eq_base(self.context.return_type):
                raise TypeMismatchException(
                    f"Trying to return base type {sub.typ}, output expecting "
                    f"{self.context.return_type}",
                    self.stmt.value,
                )
            if sub.typ.maxlen > self.context.return_type.maxlen:
                raise TypeMismatchException(
                    f"Cannot cast from greater max-length {sub.typ.maxlen} to shorter "
                    f"max-length {self.context.return_type.maxlen}",
                    self.stmt.value,
                )

            # loop memory has to be allocated first.
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType('uint256'))
            # len & bytez placeholder have to be declared after each other at all times.
            len_placeholder = self.context.new_placeholder(
                typ=BaseType('uint256'))
            bytez_placeholder = self.context.new_placeholder(typ=sub.typ)

            if sub.location in ('storage', 'memory'):
                return LLLnode.from_list([
                    'seq',
                    make_byte_array_copier(LLLnode(
                        bytez_placeholder, location='memory', typ=sub.typ),
                                           sub,
                                           pos=getpos(self.stmt)),
                    zero_pad(bytez_placeholder),
                    ['mstore', len_placeholder, 32],
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        len_placeholder,
                        ['ceil32', ['add', ['mload', bytez_placeholder], 64]],
                        loop_memory_position=loop_memory_position,
                    )
                ],
                                         typ=None,
                                         pos=getpos(self.stmt),
                                         valency=0)
            else:
                raise Exception(f"Invalid location: {sub.location}")

        elif isinstance(sub.typ, ListType):
            sub_base_type = re.split(r'\(|\[', str(sub.typ.subtype))[0]
            ret_base_type = re.split(r'\(|\[',
                                     str(self.context.return_type.subtype))[0]
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType('uint256'))
            if sub_base_type != ret_base_type:
                raise TypeMismatchException(
                    f"List return type {sub_base_type} does not match specified "
                    f"return type, expecting {ret_base_type}", self.stmt)
            elif sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list(
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    ),
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                new_sub = LLLnode.from_list(
                    self.context.new_placeholder(self.context.return_type),
                    typ=self.context.return_type,
                    location='memory',
                )
                setter = make_setter(new_sub,
                                     sub,
                                     'memory',
                                     pos=getpos(self.stmt))
                return LLLnode.from_list([
                    'seq', setter,
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        new_sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    )
                ],
                                         typ=None,
                                         pos=getpos(self.stmt))

        # Returning a struct
        elif isinstance(sub.typ, StructType):
            retty = self.context.return_type
            if not isinstance(retty, StructType) or retty.name != sub.typ.name:
                raise TypeMismatchException(
                    f"Trying to return {sub.typ}, output expecting {self.context.return_type}",
                    self.stmt.value,
                )
            return gen_tuple_return(self.stmt, self.context, sub)

        # Returning a tuple.
        elif isinstance(sub.typ, TupleType):
            if not isinstance(self.context.return_type, TupleType):
                raise TypeMismatchException(
                    f"Trying to return tuple type {sub.typ}, output expecting "
                    f"{self.context.return_type}",
                    self.stmt.value,
                )

            if len(self.context.return_type.members) != len(sub.typ.members):
                raise StructureException("Tuple lengths don't match!",
                                         self.stmt)

            # check return type matches, sub type.
            for i, ret_x in enumerate(self.context.return_type.members):
                s_member = sub.typ.members[i]
                sub_type = s_member if isinstance(s_member,
                                                  NodeType) else s_member.typ
                if type(sub_type) is not type(ret_x):
                    raise StructureException(
                        "Tuple return type does not match annotated return. "
                        f"{type(sub_type)} != {type(ret_x)}", self.stmt)
            return gen_tuple_return(self.stmt, self.context, sub)

        else:
            raise TypeMismatchException(f"Can't return type {sub.typ}",
                                        self.stmt)
Beispiel #4
0
    def parse_Return(self):
        if self.context.return_type is None:
            if self.stmt.value:
                return
            return LLLnode.from_list(
                make_return_stmt(self.stmt, self.context, 0, 0),
                typ=None,
                pos=getpos(self.stmt),
                valency=0,
            )

        sub = Expr(self.stmt.value, self.context).lll_node

        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            sub = unwrap_location(sub)

            if self.context.return_type != sub.typ and not sub.typ.is_literal:
                return
            elif sub.typ.is_literal and (
                    self.context.return_type.typ == sub.typ
                    or "int" in self.context.return_type.typ
                    and "int" in sub.typ.typ):  # noqa: E501
                if SizeLimits.in_bounds(self.context.return_type.typ,
                                        sub.value):
                    return LLLnode.from_list(
                        [
                            "seq",
                            ["mstore", 0, sub],
                            make_return_stmt(self.stmt, self.context, 0, 32),
                        ],
                        typ=None,
                        pos=getpos(self.stmt),
                        valency=0,
                    )
            elif is_base_type(sub.typ, self.context.return_type.typ) or (
                    is_base_type(sub.typ, "int128") and is_base_type(
                        self.context.return_type, "int256")):  # noqa: E501
                return LLLnode.from_list(
                    [
                        "seq", ["mstore", 0, sub],
                        make_return_stmt(self.stmt, self.context, 0, 32)
                    ],
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            return
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayLike):
            if not sub.typ.eq_base(self.context.return_type):
                return
            if sub.typ.maxlen > self.context.return_type.maxlen:
                return

            # loop memory has to be allocated first.
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType("uint256"))
            # len & bytez placeholder have to be declared after each other at all times.
            len_placeholder = self.context.new_placeholder(
                typ=BaseType("uint256"))
            bytez_placeholder = self.context.new_placeholder(typ=sub.typ)

            if sub.location in ("storage", "memory"):
                return LLLnode.from_list(
                    [
                        "seq",
                        make_byte_array_copier(
                            LLLnode(bytez_placeholder,
                                    location="memory",
                                    typ=sub.typ),
                            sub,
                            pos=getpos(self.stmt),
                        ),
                        zero_pad(bytez_placeholder),
                        ["mstore", len_placeholder, 32],
                        make_return_stmt(
                            self.stmt,
                            self.context,
                            len_placeholder,
                            [
                                "ceil32",
                                ["add", ["mload", bytez_placeholder], 64]
                            ],
                            loop_memory_position=loop_memory_position,
                        ),
                    ],
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            return

        elif isinstance(sub.typ, ListType):
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType("uint256"))
            if sub.typ != self.context.return_type:
                return
            elif sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list(
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    ),
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                new_sub = LLLnode.from_list(
                    self.context.new_placeholder(self.context.return_type),
                    typ=self.context.return_type,
                    location="memory",
                )
                setter = make_setter(new_sub,
                                     sub,
                                     "memory",
                                     pos=getpos(self.stmt))
                return LLLnode.from_list(
                    [
                        "seq",
                        setter,
                        make_return_stmt(
                            self.stmt,
                            self.context,
                            new_sub,
                            get_size_of_type(self.context.return_type) * 32,
                            loop_memory_position=loop_memory_position,
                        ),
                    ],
                    typ=None,
                    pos=getpos(self.stmt),
                )

        # Returning a struct
        elif isinstance(sub.typ, StructType):
            retty = self.context.return_type
            if isinstance(retty, StructType) and retty.name == sub.typ.name:
                return gen_tuple_return(self.stmt, self.context, sub)

        # Returning a tuple.
        elif isinstance(sub.typ, TupleType):
            if not isinstance(self.context.return_type, TupleType):
                return

            if len(self.context.return_type.members) != len(sub.typ.members):
                return

            # check return type matches, sub type.
            for i, ret_x in enumerate(self.context.return_type.members):
                s_member = sub.typ.members[i]
                sub_type = s_member if isinstance(s_member,
                                                  NodeType) else s_member.typ
                if type(sub_type) is not type(ret_x):
                    return
            return gen_tuple_return(self.stmt, self.context, sub)
Beispiel #5
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)
Beispiel #6
0
def pack_args_by_32(
    holder,
    maxlen,
    arg,
    typ,
    context,
    placeholder,
    dynamic_offset_counter=None,
    datamem_start=None,
    pos=None,
):
    """
    Copy necessary variables to pre-allocated memory section.

    :param holder: Complete holder for all args
    :param maxlen: Total length in bytes of the full arg section (static + dynamic).
    :param arg: Current arg to pack
    :param context: Context of arg
    :param placeholder: Static placeholder for static argument part.
    :param dynamic_offset_counter: position counter stored in static args.
    :param dynamic_placeholder: pointer to current position in memory to write dynamic values to.
    :param datamem_start: position where the whole datemem section starts.
    """

    if typ.size_in_bytes == 32:
        if isinstance(arg, LLLnode):
            value = unwrap_location(arg)
        else:
            value = Expr(arg, context).lll_node
            value = base_type_conversion(value, value.typ, value.typ, pos)
        holder.append(
            LLLnode.from_list(["mstore", placeholder, value],
                              location="memory"))
    elif isinstance(typ, ArrayValueAbstractType):

        if isinstance(arg, LLLnode):  # Is prealloacted variable.
            source_lll = arg
        else:
            source_lll = Expr(arg, context).lll_node

        # Set static offset, in arg slot.
        holder.append(
            LLLnode.from_list(
                ["mstore", placeholder, ["mload", dynamic_offset_counter]]))
        # Get the beginning to write the ByteArray to.
        # TODO refactor out the use of `ByteArrayLike` once old types are removed from parser
        dest_placeholder = LLLnode.from_list(
            ["add", datamem_start, ["mload", dynamic_offset_counter]],
            typ=ByteArrayLike(typ.length),
            location="memory",
            annotation="pack_args_by_32:dest_placeholder",
        )
        copier = make_byte_array_copier(dest_placeholder, source_lll, pos=pos)
        holder.append(copier)
        # Add zero padding.
        holder.append(zero_pad(dest_placeholder))

        # Increment offset counter.
        increment_counter = LLLnode.from_list(
            [
                "mstore",
                dynamic_offset_counter,
                [
                    "add",
                    [
                        "add",
                        ["mload", dynamic_offset_counter],
                        ["ceil32", ["mload", dest_placeholder]],
                    ],
                    32,
                ],
            ],
            annotation="Increment dynamic offset counter",
        )
        holder.append(increment_counter)
    elif isinstance(typ, ArrayDefinition):

        if isinstance(arg, vy_ast.Call) and arg.func.get("id") == "empty":
            # special case for `empty()` with a static-sized array
            holder.append(mzero(placeholder, typ.size_in_bytes))
            maxlen += typ.size_in_bytes - 32
            return holder, maxlen

        maxlen += (typ.length - 1) * 32
        typ = typ.value_type

        # NOTE: Below code could be refactored into iterators/getter functions for each type of
        #       repetitive loop. But seeing how each one is a unique for loop, and in which way
        #       the sub value makes the difference in each type of list clearer.

        # List from storage
        if isinstance(arg, vy_ast.Attribute) and arg.value.id == "self":
            stor_list = context.globals[arg.attr]
            size = stor_list.typ.count
            mem_offset = 0
            for i in range(0, size):
                storage_offset = i
                arg2 = LLLnode.from_list([
                    "sload",
                    [
                        "add", ["sha3_32",
                                Expr(arg, context).lll_node], storage_offset
                    ]
                ], )
                holder, maxlen = pack_args_by_32(
                    holder,
                    maxlen,
                    arg2,
                    typ,
                    context,
                    placeholder + mem_offset,
                    pos=pos,
                )
                mem_offset += typ.size_in_bytes

        # List from variable.
        elif isinstance(arg, vy_ast.Name):
            size = context.vars[arg.id].size
            pos = context.vars[arg.id].pos
            mem_offset = 0
            for _ in range(0, size):
                arg2 = LLLnode.from_list(
                    pos + mem_offset, location=context.vars[arg.id].location)
                holder, maxlen = pack_args_by_32(
                    holder,
                    maxlen,
                    arg2,
                    typ,
                    context,
                    placeholder + mem_offset,
                    pos=pos,
                )
                mem_offset += typ.size_in_bytes

        # List from list literal.
        else:
            mem_offset = 0
            for arg2 in arg.elements:
                holder, maxlen = pack_args_by_32(
                    holder,
                    maxlen,
                    arg2,
                    typ,
                    context,
                    placeholder + mem_offset,
                    pos=pos,
                )
                mem_offset += typ.size_in_bytes
    return holder, maxlen