Exemplo n.º 1
0
def raw_call(expr, args, kwargs, context):
    to, data = args
    gas, value, outsize, delegate_call = kwargs['gas'], kwargs[
        'value'], kwargs['outsize'], kwargs['delegate_call']
    if delegate_call.typ.is_literal is False:
        raise TypeMismatchException(
            'The delegate_call parameter has to be a static/literal boolean value.'
        )
    if context.is_constant:
        raise ConstancyViolationException(
            "Cannot make calls from a constant function", expr)
    if value != zero_value:
        enforce_units(value.typ, get_keyword(expr, 'value'),
                      BaseType('uint256', {'wei': 1}))
    placeholder = context.new_placeholder(data.typ)
    placeholder_node = LLLnode.from_list(placeholder,
                                         typ=data.typ,
                                         location='memory')
    copier = make_byte_array_copier(placeholder_node, data, pos=getpos(expr))
    output_placeholder = context.new_placeholder(ByteArrayType(outsize))
    output_node = LLLnode.from_list(output_placeholder,
                                    typ=ByteArrayType(outsize),
                                    location='memory')

    if delegate_call.value == 1:
        z = LLLnode.from_list([
            'seq', copier,
            [
                'assert',
                [
                    'delegatecall', gas, to, ['add', placeholder_node, 32],
                    ['mload', placeholder_node], ['add', output_node, 32],
                    outsize
                ]
            ], ['mstore', output_node, outsize], output_node
        ],
                              typ=ByteArrayType(outsize),
                              location='memory',
                              pos=getpos(expr))
    else:
        z = LLLnode.from_list([
            'seq', copier,
            [
                'assert',
                [
                    'call', gas, to, value, ['add', placeholder_node, 32],
                    ['mload', placeholder_node], ['add', output_node, 32],
                    outsize
                ]
            ], ['mstore', output_node, outsize], output_node
        ],
                              typ=ByteArrayType(outsize),
                              location='memory',
                              pos=getpos(expr))
    return z
Exemplo n.º 2
0
def _sha3(expr, args, kwargs, context):
    sub = args[0]
    # Can hash literals
    if isinstance(sub, bytes):
        return LLLnode.from_list(bytes_to_int(sha3(sub)),
                                 typ=BaseType('bytes32'),
                                 pos=getpos(expr))
    # Can hash bytes32 objects
    if is_base_type(sub.typ, 'bytes32'):
        return LLLnode.from_list([
            'seq', ['mstore', MemoryPositions.FREE_VAR_SPACE, sub],
            ['sha3', MemoryPositions.FREE_VAR_SPACE, 32]
        ],
                                 typ=BaseType('bytes32'),
                                 pos=getpos(expr))
    # Copy the data to an in-memory array
    if sub.location == "memory":
        # If we are hashing a value in memory, no need to copy it, just hash in-place
        return LLLnode.from_list([
            'with', '_sub', sub,
            ['sha3', ['add', '_sub', 32], ['mload', '_sub']]
        ],
                                 typ=BaseType('bytes32'),
                                 pos=getpos(expr))
    elif sub.location == "storage":
        lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']],
                                      typ=BaseType('int128'))
    else:
        # This should never happen, but just left here for future compiler-writers.
        raise Exception("Unsupported location: %s" %
                        sub.location)  # pragma: no test
    placeholder = context.new_placeholder(sub.typ)
    placeholder_node = LLLnode.from_list(placeholder,
                                         typ=sub.typ,
                                         location='memory')
    copier = make_byte_array_copier(
        placeholder_node,
        LLLnode.from_list('_sub', typ=sub.typ, location=sub.location))
    return LLLnode.from_list([
        'with', '_sub', sub,
        ['seq', copier, ['sha3', ['add', placeholder, 32], lengetter]]
    ],
                             typ=BaseType('bytes32'),
                             pos=getpos(expr))
Exemplo n.º 3
0
def raw_log(expr, args, kwargs, context):
    if not isinstance(args[0], ast.List) or len(args[0].elts) > 4:
        raise StructureException(
            "Expecting a list of 0-4 topics as first argument", args[0])
    topics = []
    for elt in args[0].elts:
        arg = Expr.parse_value_expr(elt, context)
        if not is_base_type(arg.typ, 'bytes32'):
            raise TypeMismatchException(
                "Expecting a bytes32 argument as topic", elt)
        topics.append(arg)
    if args[1].location == "memory":
        return LLLnode.from_list([
            "with", "_arr", args[1],
            ["log" + str(len(topics)), ["add", "_arr", 32], ["mload", "_arr"]]
            + topics
        ],
                                 typ=None,
                                 pos=getpos(expr))
    placeholder = context.new_placeholder(args[1].typ)
    placeholder_node = LLLnode.from_list(placeholder,
                                         typ=args[1].typ,
                                         location='memory')
    copier = make_byte_array_copier(placeholder_node,
                                    LLLnode.from_list(
                                        '_sub',
                                        typ=args[1].typ,
                                        location=args[1].location),
                                    pos=getpos(expr))
    return LLLnode.from_list([
        "with", "_sub", args[1],
        [
            "seq", copier,
            [
                "log" + str(len(topics)), ["add", placeholder_node, 32],
                ["mload", placeholder_node]
            ] + topics
        ]
    ],
                             typ=None,
                             pos=getpos(expr))
Exemplo n.º 4
0
def _RLPlist(expr, args, kwargs, context):
    # Second argument must be a list of types
    if not isinstance(args[1], ast.List):
        raise TypeMismatchException(
            "Expecting list of types for second argument", args[1])
    if len(args[1].elts) == 0:
        raise TypeMismatchException("RLP list must have at least one item",
                                    expr)
    if len(args[1].elts) > 32:
        raise TypeMismatchException("RLP list must have at most 32 items",
                                    expr)
    # Get the output format
    _format = []
    for arg in args[1].elts:
        if isinstance(arg, ast.Name) and arg.id == "bytes":
            subtyp = ByteArrayType(args[0].typ.maxlen)
        else:
            subtyp = parse_type(arg, 'memory')
            if not isinstance(subtyp, BaseType):
                raise TypeMismatchException(
                    "RLP lists only accept BaseTypes and byte arrays", arg)
            if not is_base_type(
                    subtyp,
                ('int128', 'uint256', 'bytes32', 'address', 'bool')):
                raise TypeMismatchException(
                    "Unsupported base type: %s" % subtyp.typ, arg)
        _format.append(subtyp)
    output_type = TupleType(_format)
    output_placeholder_type = ByteArrayType(
        (2 * len(_format) + 1 + get_size_of_type(output_type)) * 32)
    output_placeholder = context.new_placeholder(output_placeholder_type)
    output_node = LLLnode.from_list(output_placeholder,
                                    typ=output_placeholder_type,
                                    location='memory')
    # Create a decoder for each element in the tuple
    decoder = []
    for i, typ in enumerate(_format):
        # Decoder for bytes32
        if is_base_type(typ, 'bytes32'):
            decoder.append(
                LLLnode.from_list(
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq',
                                [
                                    'mload',
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ], 32
                            ]
                        ],
                        [
                            'mload',
                            [
                                'add', 32,
                                [
                                    'add', output_node,
                                    ['mload', ['add', output_node, 32 * i]]
                                ]
                            ]
                        ]
                    ],
                    typ,
                    annotation='getting and checking bytes32 item'))
        # Decoder for address
        elif is_base_type(typ, 'address'):
            decoder.append(
                LLLnode.from_list(
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq',
                                [
                                    'mload',
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ], 20
                            ]
                        ],
                        [
                            'mod',
                            [
                                'mload',
                                [
                                    'add', 20,
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ]
                            ], ['mload', MemoryPositions.ADDRSIZE]
                        ]
                    ],
                    typ,
                    annotation='getting and checking address item'))
        # Decoder for bytes
        elif isinstance(typ, ByteArrayType):
            decoder.append(
                LLLnode.from_list([
                    'add', output_node,
                    ['mload', ['add', output_node, 32 * i]]
                ],
                                  typ,
                                  location='memory',
                                  annotation='getting byte array'))
        # Decoder for num and uint256
        elif is_base_type(typ, ('int128', 'uint256')):
            bytez = LLLnode.from_list(
                ['add', output_node, ['mload', ['add', output_node, 32 * i]]],
                typ,
                location='memory',
                annotation='getting and checking %s' % typ.typ)
            decoder.append(byte_array_to_num(bytez, expr, typ.typ))
        # Decoder for bools
        elif is_base_type(typ, ('bool')):
            # This is basically a really clever way to test for a length-prefixed one or zero. We take the 32 bytes
            # starting one byte *after* the start of the length declaration; this includes the last 31 bytes of the
            # length and the first byte of the value. 0 corresponds to length 0, first byte 0, and 257 corresponds
            # to length 1, first byte \x01
            decoder.append(
                LLLnode.from_list([
                    'with', '_ans',
                    [
                        'mload',
                        [
                            'add', 1,
                            [
                                'add', output_node,
                                ['mload', ['add', output_node, 32 * i]]
                            ]
                        ]
                    ],
                    [
                        'seq',
                        [
                            'assert',
                            ['or', ['eq', '_ans', 0], ['eq', '_ans', 257]]
                        ], ['div', '_ans', 257]
                    ]
                ],
                                  typ,
                                  annotation='getting and checking bool'))
        else:
            # Should never reach because of top level base level check.
            raise Exception("Type not yet supported")  # pragma: no cover
    # Copy the input data to memory
    if args[0].location == "memory":
        variable_pointer = args[0]
    elif args[0].location == "storage":
        placeholder = context.new_placeholder(args[0].typ)
        placeholder_node = LLLnode.from_list(placeholder,
                                             typ=args[0].typ,
                                             location='memory')
        copier = make_byte_array_copier(
            placeholder_node,
            LLLnode.from_list('_ptr',
                              typ=args[0].typ,
                              location=args[0].location))
        variable_pointer = [
            'with', '_ptr', args[0], ['seq', copier, placeholder_node]
        ]
    else:
        # Should never reach because of top level base level check.
        raise Exception("Location not yet supported")  # pragma: no cover
    # Decode the input data
    initial_setter = LLLnode.from_list([
        'seq',
        [
            'with', '_sub', variable_pointer,
            [
                'pop',
                [
                    'call', 1500 + 400 * len(_format) + 10 * len(args),
                    LLLnode.from_list(RLP_DECODER_ADDRESS,
                                      annotation='RLP decoder'), 0,
                    ['add', '_sub', 32], ['mload', '_sub'], output_node,
                    64 * len(_format) + 32 + 32 * get_size_of_type(output_type)
                ]
            ]
        ], ['assert', ['eq', ['mload', output_node], 32 * len(_format) + 32]]
    ],
                                       typ=None)
    # Shove the input data decoder in front of the first variable decoder
    decoder[0] = LLLnode.from_list(['seq', initial_setter, decoder[0]],
                                   typ=decoder[0].typ,
                                   location=decoder[0].location)
    return LLLnode.from_list(["multi"] + decoder,
                             typ=output_type,
                             location='memory',
                             pos=getpos(expr))
Exemplo n.º 5
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):
        value = parse_expr(arg, context)
        value = base_type_conversion(value, value.typ, typ, pos)
        holder.append(
            LLLnode.from_list(['mstore', placeholder, value],
                              typ=typ,
                              location='memory'))
    elif isinstance(typ, ByteArrayType):
        bytez = b''

        source_expr = Expr(arg, context)
        if isinstance(arg, ast.Str):
            if len(arg.s) > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (len(arg.s), typ),
                    pos)
            for c in arg.s:
                if ord(c) >= 256:
                    raise InvalidLiteralException(
                        "Cannot insert special character %r into byte array" %
                        c, pos)
                bytez += bytes([ord(c)])

            holder.append(source_expr.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_expr.lll_node,
                                        pos=pos)
        holder.append(copier)
        # Add zero padding.
        new_maxlen = ceil32(source_expr.lll_node.typ.maxlen)

        holder.append([
            'with',
            '_bytearray_loc',
            dest_placeholder,
            [
                'seq',
                [
                    'repeat',
                    zero_pad_i,
                    ['mload', '_bytearray_loc'],
                    new_maxlen,
                    [
                        'seq',
                        [
                            'if', ['ge', ['mload', zero_pad_i], new_maxlen],
                            'break'
                        ],  # stay within allocated bounds
                        [
                            'mstore8',
                            [
                                'add', ['add', '_bytearray_loc', 32],
                                ['mload', zero_pad_i]
                            ], 0
                        ]
                    ]
                ]
            ]
        ])
        # Increment offset counter.
        increment_counter = LLLnode.from_list([
            'mstore', dynamic_offset_counter,
            [
                'add',
                [
                    'add', ['mload', dynamic_offset_counter],
                    ['ceil32', ['mload', dest_placeholder]]
                ], 32
            ]
        ])
        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))

        # 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
            for offset in range(0, size):
                arg2 = LLLnode.from_list([
                    'sload',
                    ['add', ['sha3_32', Expr(arg, context).lll_node], offset]
                ],
                                         typ=typ)
                p_holder = context.new_placeholder(
                    BaseType(32)) if offset > 0 else placeholder
                holder, maxlen = pack_args_by_32(holder,
                                                 maxlen,
                                                 arg2,
                                                 typ,
                                                 context,
                                                 p_holder,
                                                 pos=pos)
        # 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)
            for i in range(0, size):
                offset = 32 * i
                arg2 = LLLnode.from_list(pos + offset,
                                         typ=typ,
                                         location='memory')
                p_holder = context.new_placeholder(
                    BaseType(32)) if i > 0 else placeholder
                holder, maxlen = pack_args_by_32(holder,
                                                 maxlen,
                                                 arg2,
                                                 typ,
                                                 context,
                                                 p_holder,
                                                 pos=pos)
        # is list literal.
        else:
            holder, maxlen = pack_args_by_32(holder,
                                             maxlen,
                                             arg.elts[0],
                                             typ,
                                             context,
                                             placeholder,
                                             pos=pos)
            for j, arg2 in enumerate(arg.elts[1:]):
                holder, maxlen = pack_args_by_32(holder,
                                                 maxlen,
                                                 arg2,
                                                 typ,
                                                 context,
                                                 context.new_placeholder(
                                                     BaseType(32)),
                                                 pos=pos)

    return holder, maxlen
Exemplo n.º 6
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(self.make_return_stmt(0, 0), typ=None, pos=getpos(self.stmt))
        if not self.stmt.value:
            raise TypeMismatchException("Expecting to return a value", self.stmt)

        def zero_pad(bytez_placeholder, maxlen):
            zero_padder = LLLnode.from_list(['pass'])
            if maxlen > 0:
                zero_pad_i = self.context.new_placeholder(BaseType('uint256'))  # Iterator used to zero pad memory.
                zero_padder = LLLnode.from_list(
                    ['repeat', zero_pad_i, ['mload', bytez_placeholder], maxlen,
                        ['seq',
                            ['if', ['gt', ['mload', zero_pad_i], maxlen], 'break'],  # stay within allocated bounds
                            ['mstore8', ['add', ['add', 32, bytez_placeholder], ['mload', zero_pad_i]], 0]]],
                    annotation="Zero pad"
                )
            return zero_padder

        sub = Expr(self.stmt.value, self.context).lll_node
        self.context.increment_return_counter()
        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            if not isinstance(self.context.return_type, BaseType):
                raise TypeMismatchException("Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value)
            sub = unwrap_location(sub)
            if not are_units_compatible(sub.typ, self.context.return_type):
                raise TypeMismatchException("Return type units mismatch %r %r" % (sub.typ, 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):
                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], self.make_return_stmt(0, 32)], typ=None, pos=getpos(self.stmt))
            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')):
                return LLLnode.from_list(['seq', ['mstore', 0, sub], self.make_return_stmt(0, 32)], typ=None, pos=getpos(self.stmt))
            else:
                raise TypeMismatchException("Unsupported type conversion: %r to %r" % (sub.typ, self.context.return_type), self.stmt.value)
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayType):
            if not isinstance(self.context.return_type, ByteArrayType):
                raise TypeMismatchException("Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value)
            if sub.typ.maxlen > self.context.return_type.maxlen:
                raise TypeMismatchException("Cannot cast from greater max-length %d to shorter max-length %d" %
                                            (sub.typ.maxlen, self.context.return_type.maxlen), self.stmt.value)

            loop_memory_position = self.context.new_placeholder(typ=BaseType('uint256'))  # loop memory has to be allocated first.
            len_placeholder = self.context.new_placeholder(typ=BaseType('uint256'))  # len & bytez placeholder have to be declared after each other at all times.
            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, sub.typ.maxlen),
                    ['mstore', len_placeholder, 32],
                    self.make_return_stmt(len_placeholder, ['ceil32', ['add', ['mload', bytez_placeholder], 64]], loop_memory_position=loop_memory_position)],
                    typ=None, pos=getpos(self.stmt)
                )
            else:
                raise Exception("Invalid location: %s" % 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(
                    "List return type %r does not match specified return type, expecting %r" % (
                        sub_base_type, ret_base_type
                    ),
                    self.stmt
                )
            elif sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list(self.make_return_stmt(sub, get_size_of_type(self.context.return_type) * 32, loop_memory_position=loop_memory_position),
                                            typ=None, pos=getpos(self.stmt))
            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, self.make_return_stmt(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 tuple.
        elif isinstance(sub.typ, TupleType):
            if not isinstance(self.context.return_type, TupleType):
                raise TypeMismatchException("Trying to return tuple type %r, output expecting %r" % (sub.typ, 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. {} != {}".format(
                            type(sub_type), type(ret_x)
                        ),
                        self.stmt
                    )

            # Is from a call expression.
            if 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.members) if isinstance(x, ByteArrayType)]
                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)
                return LLLnode.from_list(
                    ['seq'] +
                    [sub] +
                    [zero_padder] +
                    [self.make_return_stmt(mem_pos, mem_size)
                ], typ=sub.typ, pos=getpos(self.stmt))

            subs = []
            # Pre-allocate loop_memory_position if required for private function returning.
            loop_memory_position = self.context.new_placeholder(typ=BaseType('uint256')) if self.context.is_private else None
            # Allocate dynamic off set counter, to keep track of the total packed dynamic data size.
            dynamic_offset_counter_placeholder = self.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(
                self.context.new_placeholder(typ=BaseType('uint256')), typ=self.context.return_type, location='memory', annotation='new_sub'
            )
            keyz = list(range(len(sub.typ.members)))
            dynamic_offset_start = 32 * len(sub.args)  # The static list of args end.
            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]]
                ]

            for i, typ in enumerate(keyz):
                arg = sub.args[i]
                variable_offset = LLLnode.from_list(['add', 32 * i, left_token], typ=arg.typ, annotation='variable_offset')
                if isinstance(arg.typ, ByteArrayType):
                    # 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=arg.typ, annotation='dynamic_spot')
                    subs.append(make_setter(dynamic_spot, arg, location="memory", pos=getpos(self.stmt)))
                    subs.append(increment_dynamic_offset(dynamic_spot))

                elif isinstance(arg.typ, BaseType):
                    subs.append(make_setter(variable_offset, arg, "memory", pos=getpos(self.stmt)))
                else:
                    raise Exception("Can't return type %s as part of tuple", type(arg.typ))

            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,
                    self.make_return_stmt(new_sub, get_dynamic_offset_value(), loop_memory_position)],
                typ=None, pos=getpos(self.stmt)
            )
        else:
            raise TypeMismatchException("Can only return base type!", self.stmt)