We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Fails: Using empty `bytes[256]` default function parameter on internal constant and private functions
### Version Information

* vyper Version: 0.1.0b10
* OS: osx
* Python Version: 3.7.3

### What's your issue about?

Calling `mint()` on the following contract throws when making use of the default parameters:

```python
@private
@constant
def _checkForERC777TokensInterface_Recipient(
    _to: address,
    _amount: uint256,
    _data: bytes[256]="",
  ):
    assert True


@public
def mint(
    _to: address,
    _amount: uint256,
    _data: bytes[256]="",
  ):
    # NOTE: fails (stack underflow) because of default _data parameter
    self._checkForERC777TokensInterface_Recipient(
      _to,
      _amount,
      _data,
    )
```

#### Using `web3js`:

This throws: `Error: Returned error: VM Exception while processing transaction: stack underflow`
```javascript
await erc777Token.mint(
      wallet.address,
      100,
    );
```

This works:
```javascript
    await erc777Token.mint(
      wallet.address,
      100,
      '0x0000000000000000000000000000000000000001',
    );
```

### How can this be solved?

I posted a solution further down (use `data: bytes[256]="0x0"` in `mint()`). 
Maybe everything is fine and one should just not use default parameters in internal functions...
In that case this issue can be closed.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vyper/parser/self_call.py`
Content:
```
1 import itertools
2 
3 from vyper.exceptions import (
4     ConstancyViolationException,
5 )
6 from vyper.parser.lll_node import (
7     LLLnode,
8 )
9 from vyper.parser.parser_utils import (
10     getpos,
11     pack_arguments,
12 )
13 from vyper.signatures.function_signature import (
14     FunctionSignature,
15 )
16 from vyper.types import (
17     BaseType,
18     ByteArrayLike,
19     ListType,
20     TupleLike,
21     ceil32,
22     get_size_of_type,
23     get_static_size_of_type,
24 )
25 
26 
27 def call_lookup_specs(stmt_expr, context):
28     from vyper.parser.expr import Expr
29     method_name = stmt_expr.func.attr
30     expr_args = [Expr(arg, context).lll_node for arg in stmt_expr.args]
31     sig = FunctionSignature.lookup_sig(context.sigs, method_name, expr_args, stmt_expr, context)
32     return method_name, expr_args, sig
33 
34 
35 def make_call(stmt_expr, context):
36     method_name, _, sig = call_lookup_specs(stmt_expr, context)
37 
38     if context.is_constant() and not sig.const:
39         raise ConstancyViolationException(
40             "May not call non-constant function '%s' within %s." % (
41                 method_name,
42                 context.pp_constancy(),
43             ),
44             getpos(stmt_expr)
45         )
46 
47     if sig.private:
48         return call_self_private(stmt_expr, context, sig)
49     else:
50         return call_self_public(stmt_expr, context, sig)
51 
52 
53 def call_make_placeholder(stmt_expr, context, sig):
54     if sig.output_type is None:
55         return 0, 0, 0
56 
57     output_placeholder = context.new_placeholder(typ=sig.output_type)
58     out_size = get_size_of_type(sig.output_type) * 32
59     returner = output_placeholder
60 
61     if not sig.private and isinstance(sig.output_type, ByteArrayLike):
62         returner = output_placeholder + 32
63 
64     return output_placeholder, returner, out_size
65 
66 
67 def call_self_private(stmt_expr, context, sig):
68     # ** Private Call **
69     # Steps:
70     # (x) push current local variables
71     # (x) push arguments
72     # (x) push jumpdest (callback ptr)
73     # (x) jump to label
74     # (x) pop return values
75     # (x) pop local variables
76 
77     method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)
78     pre_init = []
79     pop_local_vars = []
80     push_local_vars = []
81     pop_return_values = []
82     push_args = []
83 
84     # Push local variables.
85     if context.vars:
86         var_slots = [(v.pos, v.size) for name, v in context.vars.items()]
87         var_slots.sort(key=lambda x: x[0])
88         mem_from, mem_to = var_slots[0][0], var_slots[-1][0] + var_slots[-1][1] * 32
89         push_local_vars = [
90             ['mload', pos] for pos in range(mem_from, mem_to, 32)
91         ]
92         pop_local_vars = [
93             ['mstore', pos, 'pass'] for pos in reversed(range(mem_from, mem_to, 32))
94         ]
95 
96     # Push Arguments
97     if expr_args:
98         inargs, inargsize, arg_pos = pack_arguments(
99             sig,
100             expr_args,
101             context,
102             return_placeholder=False,
103             pos=getpos(stmt_expr),
104         )
105         push_args += [inargs]  # copy arguments first, to not mess up the push/pop sequencing.
106 
107         static_arg_size = 32 * sum(
108                 [get_static_size_of_type(arg.typ)
109                     for arg in expr_args])
110         static_pos = arg_pos + static_arg_size
111         total_arg_size = ceil32(inargsize - 4)
112 
113         if static_arg_size != total_arg_size:  # requires dynamic section.
114             ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)
115             start_label = ident + '_start'
116             end_label = ident + '_end'
117             i_placeholder = context.new_placeholder(BaseType('uint256'))
118             push_args += [
119                 ['mstore', i_placeholder, arg_pos + total_arg_size],
120                 ['label', start_label],
121                 ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],
122                 [
123                     'if_unchecked',
124                     ['ne', ['mload', ['mload', i_placeholder]], 0],
125                     ['mload', ['mload', i_placeholder]],
126                 ],
127                 ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i
128                 ['goto', start_label],
129                 ['label', end_label]
130             ]
131 
132         # push static section
133         push_args += [
134             ['mload', pos] for pos in reversed(range(arg_pos, static_pos, 32))
135         ]
136 
137     # Jump to function label.
138     jump_to_func = [
139         ['add', ['pc'], 6],  # set callback pointer.
140         ['goto', 'priv_{}'.format(sig.method_id)],
141         ['jumpdest'],
142     ]
143 
144     # Pop return values.
145     returner = [0]
146     if sig.output_type:
147         output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)
148         if output_size > 0:
149             dynamic_offsets = []
150             if isinstance(sig.output_type, (BaseType, ListType)):
151                 pop_return_values = [
152                     ['mstore', ['add', output_placeholder, pos], 'pass']
153                     for pos in range(0, output_size, 32)
154                 ]
155             elif isinstance(sig.output_type, ByteArrayLike):
156                 dynamic_offsets = [(0, sig.output_type)]
157                 pop_return_values = [
158                     ['pop', 'pass'],
159                 ]
160             elif isinstance(sig.output_type, TupleLike):
161                 static_offset = 0
162                 pop_return_values = []
163                 for out_type in sig.output_type.members:
164                     if isinstance(out_type, ByteArrayLike):
165                         pop_return_values.append(
166                             ['mstore', ['add', output_placeholder, static_offset], 'pass']
167                         )
168                         dynamic_offsets.append(
169                             (['mload', ['add', output_placeholder, static_offset]], out_type)
170                         )
171                     else:
172                         pop_return_values.append(
173                             ['mstore', ['add', output_placeholder, static_offset], 'pass']
174                         )
175                     static_offset += 32
176 
177             # append dynamic unpacker.
178             dyn_idx = 0
179             for in_memory_offset, _out_type in dynamic_offsets:
180                 ident = "%d_%d_arg_%d" % (stmt_expr.lineno, stmt_expr.col_offset, dyn_idx)
181                 dyn_idx += 1
182                 start_label = 'dyn_unpack_start_' + ident
183                 end_label = 'dyn_unpack_end_' + ident
184                 i_placeholder = context.new_placeholder(typ=BaseType('uint256'))
185                 begin_pos = ['add', output_placeholder, in_memory_offset]
186                 # loop until length.
187                 o = LLLnode.from_list(
188                     ['seq_unchecked',
189                         ['mstore', begin_pos, 'pass'],  # get len
190                         ['mstore', i_placeholder, 0],
191                         ['label', start_label],
192                         [  # break
193                             'if',
194                             ['ge', ['mload', i_placeholder], ['ceil32', ['mload', begin_pos]]],
195                             ['goto', end_label]
196                         ],
197                         [  # pop into correct memory slot.
198                             'mstore',
199                             ['add', ['add', begin_pos, 32], ['mload', i_placeholder]],
200                             'pass',
201                         ],
202                         # increment i
203                         ['mstore', i_placeholder, ['add', 32, ['mload', i_placeholder]]],
204                         ['goto', start_label],
205                         ['label', end_label]],
206                     typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))
207                 pop_return_values.append(o)
208 
209     call_body = list(itertools.chain(
210         ['seq_unchecked'],
211         pre_init,
212         push_local_vars,
213         push_args,
214         jump_to_func,
215         pop_return_values,
216         pop_local_vars,
217         [returner],
218     ))
219     # If we have no return, we need to pop off
220     pop_returner_call_body = ['pop', call_body] if sig.output_type is None else call_body
221 
222     o = LLLnode.from_list(
223         pop_returner_call_body,
224         typ=sig.output_type,
225         location='memory',
226         pos=getpos(stmt_expr),
227         annotation='Internal Call: %s' % method_name,
228         add_gas_estimate=sig.gas
229     )
230     o.gas += sig.gas
231     return o
232 
233 
234 def call_self_public(stmt_expr, context, sig):
235     # self.* style call to a public function.
236     method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)
237     add_gas = sig.gas  # gas of call
238     inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr))
239     output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)
240     assert_call = [
241         'assert',
242         ['call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size],
243     ]
244     if output_size > 0:
245         assert_call = ['seq', assert_call, returner]
246     o = LLLnode.from_list(
247         assert_call,
248         typ=sig.output_type,
249         location='memory',
250         pos=getpos(stmt_expr),
251         add_gas_estimate=add_gas,
252         annotation='Internal Call: %s' % method_name,
253     )
254     o.gas += sig.gas
255     return o
256
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/vyper/parser/self_call.py b/vyper/parser/self_call.py
--- a/vyper/parser/self_call.py
+++ b/vyper/parser/self_call.py
@@ -18,9 +18,9 @@
     ByteArrayLike,
     ListType,
     TupleLike,
-    ceil32,
     get_size_of_type,
     get_static_size_of_type,
+    has_dynamic_data,
 )
 
 
@@ -108,22 +108,42 @@
                 [get_static_size_of_type(arg.typ)
                     for arg in expr_args])
         static_pos = arg_pos + static_arg_size
-        total_arg_size = ceil32(inargsize - 4)
+        needs_dyn_section = any(
+                [has_dynamic_data(arg.typ)
+                    for arg in expr_args])
 
-        if static_arg_size != total_arg_size:  # requires dynamic section.
+        if needs_dyn_section:
             ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)
             start_label = ident + '_start'
             end_label = ident + '_end'
             i_placeholder = context.new_placeholder(BaseType('uint256'))
+
+            # Calculate copy start position.
+            # Given | static | dynamic | section in memory,
+            # copy backwards so the values are in order on the stack.
+            # We calculate i, the end of the whole encoded part
+            # (i.e. the starting index for copy)
+            # by taking ceil32(len<arg>) + offset<arg> + arg_pos
+            # for the last dynamic argument and arg_pos is the start
+            # the whole argument section.
+            for idx, arg in enumerate(expr_args):
+                if isinstance(arg.typ, ByteArrayLike):
+                    last_idx = idx
             push_args += [
-                ['mstore', i_placeholder, arg_pos + total_arg_size],
+                ['with', 'offset', ['mload', arg_pos + last_idx * 32],
+                    ['with', 'len_pos', ['add', arg_pos, 'offset'],
+                        ['with', 'len_value', ['mload', 'len_pos'],
+                            ['mstore', i_placeholder,
+                                ['add', 'len_pos', ['ceil32', 'len_value']]]]]]
+            ]
+            # loop from end of dynamic section to start of dynamic section,
+            # pushing each element onto the stack.
+            push_args += [
+
                 ['label', start_label],
-                ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],
-                [
-                    'if_unchecked',
-                    ['ne', ['mload', ['mload', i_placeholder]], 0],
-                    ['mload', ['mload', i_placeholder]],
-                ],
+                ['if', ['lt', ['mload', i_placeholder], static_pos],
+                    ['goto', end_label]],
+                ['mload', ['mload', i_placeholder]],
                 ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i
                 ['goto', start_label],
                 ['label', end_label]

{"golden_diff": "diff --git a/vyper/parser/self_call.py b/vyper/parser/self_call.py\n--- a/vyper/parser/self_call.py\n+++ b/vyper/parser/self_call.py\n@@ -18,9 +18,9 @@\n     ByteArrayLike,\n     ListType,\n     TupleLike,\n-    ceil32,\n     get_size_of_type,\n     get_static_size_of_type,\n+    has_dynamic_data,\n )\n \n \n@@ -108,22 +108,42 @@\n                 [get_static_size_of_type(arg.typ)\n                     for arg in expr_args])\n         static_pos = arg_pos + static_arg_size\n-        total_arg_size = ceil32(inargsize - 4)\n+        needs_dyn_section = any(\n+                [has_dynamic_data(arg.typ)\n+                    for arg in expr_args])\n \n-        if static_arg_size != total_arg_size:  # requires dynamic section.\n+        if needs_dyn_section:\n             ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)\n             start_label = ident + '_start'\n             end_label = ident + '_end'\n             i_placeholder = context.new_placeholder(BaseType('uint256'))\n+\n+            # Calculate copy start position.\n+            # Given | static | dynamic | section in memory,\n+            # copy backwards so the values are in order on the stack.\n+            # We calculate i, the end of the whole encoded part\n+            # (i.e. the starting index for copy)\n+            # by taking ceil32(len<arg>) + offset<arg> + arg_pos\n+            # for the last dynamic argument and arg_pos is the start\n+            # the whole argument section.\n+            for idx, arg in enumerate(expr_args):\n+                if isinstance(arg.typ, ByteArrayLike):\n+                    last_idx = idx\n             push_args += [\n-                ['mstore', i_placeholder, arg_pos + total_arg_size],\n+                ['with', 'offset', ['mload', arg_pos + last_idx * 32],\n+                    ['with', 'len_pos', ['add', arg_pos, 'offset'],\n+                        ['with', 'len_value', ['mload', 'len_pos'],\n+                            ['mstore', i_placeholder,\n+                                ['add', 'len_pos', ['ceil32', 'len_value']]]]]]\n+            ]\n+            # loop from end of dynamic section to start of dynamic section,\n+            # pushing each element onto the stack.\n+            push_args += [\n+\n                 ['label', start_label],\n-                ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],\n-                [\n-                    'if_unchecked',\n-                    ['ne', ['mload', ['mload', i_placeholder]], 0],\n-                    ['mload', ['mload', i_placeholder]],\n-                ],\n+                ['if', ['lt', ['mload', i_placeholder], static_pos],\n+                    ['goto', end_label]],\n+                ['mload', ['mload', i_placeholder]],\n                 ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i\n                 ['goto', start_label],\n                 ['label', end_label]\n", "issue": "Fails: Using empty `bytes[256]` default function parameter on internal constant and private functions\n### Version Information\r\n\r\n* vyper Version: 0.1.0b10\r\n* OS: osx\r\n* Python Version: 3.7.3\r\n\r\n### What's your issue about?\r\n\r\nCalling `mint()` on the following contract throws when making use of the default parameters:\r\n\r\n```python\r\n@private\r\n@constant\r\ndef _checkForERC777TokensInterface_Recipient(\r\n    _to: address,\r\n    _amount: uint256,\r\n    _data: bytes[256]=\"\",\r\n  ):\r\n    assert True\r\n\r\n\r\n@public\r\ndef mint(\r\n    _to: address,\r\n    _amount: uint256,\r\n    _data: bytes[256]=\"\",\r\n  ):\r\n    # NOTE: fails (stack underflow) because of default _data parameter\r\n    self._checkForERC777TokensInterface_Recipient(\r\n      _to,\r\n      _amount,\r\n      _data,\r\n    )\r\n```\r\n\r\n#### Using `web3js`:\r\n\r\nThis throws: `Error: Returned error: VM Exception while processing transaction: stack underflow`\r\n```javascript\r\nawait erc777Token.mint(\r\n      wallet.address,\r\n      100,\r\n    );\r\n```\r\n\r\nThis works:\r\n```javascript\r\n    await erc777Token.mint(\r\n      wallet.address,\r\n      100,\r\n      '0x0000000000000000000000000000000000000001',\r\n    );\r\n```\r\n\r\n### How can this be solved?\r\n\r\nI posted a solution further down (use `data: bytes[256]=\"0x0\"` in `mint()`). \r\nMaybe everything is fine and one should just not use default parameters in internal functions...\r\nIn that case this issue can be closed.\r\n\n", "before_files": [{"content": "import itertools\n\nfrom vyper.exceptions import (\n    ConstancyViolationException,\n)\nfrom vyper.parser.lll_node import (\n    LLLnode,\n)\nfrom vyper.parser.parser_utils import (\n    getpos,\n    pack_arguments,\n)\nfrom vyper.signatures.function_signature import (\n    FunctionSignature,\n)\nfrom vyper.types import (\n    BaseType,\n    ByteArrayLike,\n    ListType,\n    TupleLike,\n    ceil32,\n    get_size_of_type,\n    get_static_size_of_type,\n)\n\n\ndef call_lookup_specs(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    method_name = stmt_expr.func.attr\n    expr_args = [Expr(arg, context).lll_node for arg in stmt_expr.args]\n    sig = FunctionSignature.lookup_sig(context.sigs, method_name, expr_args, stmt_expr, context)\n    return method_name, expr_args, sig\n\n\ndef make_call(stmt_expr, context):\n    method_name, _, sig = call_lookup_specs(stmt_expr, context)\n\n    if context.is_constant() and not sig.const:\n        raise ConstancyViolationException(\n            \"May not call non-constant function '%s' within %s.\" % (\n                method_name,\n                context.pp_constancy(),\n            ),\n            getpos(stmt_expr)\n        )\n\n    if sig.private:\n        return call_self_private(stmt_expr, context, sig)\n    else:\n        return call_self_public(stmt_expr, context, sig)\n\n\ndef call_make_placeholder(stmt_expr, context, sig):\n    if sig.output_type is None:\n        return 0, 0, 0\n\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    out_size = get_size_of_type(sig.output_type) * 32\n    returner = output_placeholder\n\n    if not sig.private and isinstance(sig.output_type, ByteArrayLike):\n        returner = output_placeholder + 32\n\n    return output_placeholder, returner, out_size\n\n\ndef call_self_private(stmt_expr, context, sig):\n    # ** Private Call **\n    # Steps:\n    # (x) push current local variables\n    # (x) push arguments\n    # (x) push jumpdest (callback ptr)\n    # (x) jump to label\n    # (x) pop return values\n    # (x) pop local variables\n\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    pre_init = []\n    pop_local_vars = []\n    push_local_vars = []\n    pop_return_values = []\n    push_args = []\n\n    # Push local variables.\n    if context.vars:\n        var_slots = [(v.pos, v.size) for name, v in context.vars.items()]\n        var_slots.sort(key=lambda x: x[0])\n        mem_from, mem_to = var_slots[0][0], var_slots[-1][0] + var_slots[-1][1] * 32\n        push_local_vars = [\n            ['mload', pos] for pos in range(mem_from, mem_to, 32)\n        ]\n        pop_local_vars = [\n            ['mstore', pos, 'pass'] for pos in reversed(range(mem_from, mem_to, 32))\n        ]\n\n    # Push Arguments\n    if expr_args:\n        inargs, inargsize, arg_pos = pack_arguments(\n            sig,\n            expr_args,\n            context,\n            return_placeholder=False,\n            pos=getpos(stmt_expr),\n        )\n        push_args += [inargs]  # copy arguments first, to not mess up the push/pop sequencing.\n\n        static_arg_size = 32 * sum(\n                [get_static_size_of_type(arg.typ)\n                    for arg in expr_args])\n        static_pos = arg_pos + static_arg_size\n        total_arg_size = ceil32(inargsize - 4)\n\n        if static_arg_size != total_arg_size:  # requires dynamic section.\n            ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)\n            start_label = ident + '_start'\n            end_label = ident + '_end'\n            i_placeholder = context.new_placeholder(BaseType('uint256'))\n            push_args += [\n                ['mstore', i_placeholder, arg_pos + total_arg_size],\n                ['label', start_label],\n                ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],\n                [\n                    'if_unchecked',\n                    ['ne', ['mload', ['mload', i_placeholder]], 0],\n                    ['mload', ['mload', i_placeholder]],\n                ],\n                ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i\n                ['goto', start_label],\n                ['label', end_label]\n            ]\n\n        # push static section\n        push_args += [\n            ['mload', pos] for pos in reversed(range(arg_pos, static_pos, 32))\n        ]\n\n    # Jump to function label.\n    jump_to_func = [\n        ['add', ['pc'], 6],  # set callback pointer.\n        ['goto', 'priv_{}'.format(sig.method_id)],\n        ['jumpdest'],\n    ]\n\n    # Pop return values.\n    returner = [0]\n    if sig.output_type:\n        output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n        if output_size > 0:\n            dynamic_offsets = []\n            if isinstance(sig.output_type, (BaseType, ListType)):\n                pop_return_values = [\n                    ['mstore', ['add', output_placeholder, pos], 'pass']\n                    for pos in range(0, output_size, 32)\n                ]\n            elif isinstance(sig.output_type, ByteArrayLike):\n                dynamic_offsets = [(0, sig.output_type)]\n                pop_return_values = [\n                    ['pop', 'pass'],\n                ]\n            elif isinstance(sig.output_type, TupleLike):\n                static_offset = 0\n                pop_return_values = []\n                for out_type in sig.output_type.members:\n                    if isinstance(out_type, ByteArrayLike):\n                        pop_return_values.append(\n                            ['mstore', ['add', output_placeholder, static_offset], 'pass']\n                        )\n                        dynamic_offsets.append(\n                            (['mload', ['add', output_placeholder, static_offset]], out_type)\n                        )\n                    else:\n                        pop_return_values.append(\n                            ['mstore', ['add', output_placeholder, static_offset], 'pass']\n                        )\n                    static_offset += 32\n\n            # append dynamic unpacker.\n            dyn_idx = 0\n            for in_memory_offset, _out_type in dynamic_offsets:\n                ident = \"%d_%d_arg_%d\" % (stmt_expr.lineno, stmt_expr.col_offset, dyn_idx)\n                dyn_idx += 1\n                start_label = 'dyn_unpack_start_' + ident\n                end_label = 'dyn_unpack_end_' + ident\n                i_placeholder = context.new_placeholder(typ=BaseType('uint256'))\n                begin_pos = ['add', output_placeholder, in_memory_offset]\n                # loop until length.\n                o = LLLnode.from_list(\n                    ['seq_unchecked',\n                        ['mstore', begin_pos, 'pass'],  # get len\n                        ['mstore', i_placeholder, 0],\n                        ['label', start_label],\n                        [  # break\n                            'if',\n                            ['ge', ['mload', i_placeholder], ['ceil32', ['mload', begin_pos]]],\n                            ['goto', end_label]\n                        ],\n                        [  # pop into correct memory slot.\n                            'mstore',\n                            ['add', ['add', begin_pos, 32], ['mload', i_placeholder]],\n                            'pass',\n                        ],\n                        # increment i\n                        ['mstore', i_placeholder, ['add', 32, ['mload', i_placeholder]]],\n                        ['goto', start_label],\n                        ['label', end_label]],\n                    typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))\n                pop_return_values.append(o)\n\n    call_body = list(itertools.chain(\n        ['seq_unchecked'],\n        pre_init,\n        push_local_vars,\n        push_args,\n        jump_to_func,\n        pop_return_values,\n        pop_local_vars,\n        [returner],\n    ))\n    # If we have no return, we need to pop off\n    pop_returner_call_body = ['pop', call_body] if sig.output_type is None else call_body\n\n    o = LLLnode.from_list(\n        pop_returner_call_body,\n        typ=sig.output_type,\n        location='memory',\n        pos=getpos(stmt_expr),\n        annotation='Internal Call: %s' % method_name,\n        add_gas_estimate=sig.gas\n    )\n    o.gas += sig.gas\n    return o\n\n\ndef call_self_public(stmt_expr, context, sig):\n    # self.* style call to a public function.\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    add_gas = sig.gas  # gas of call\n    inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr))\n    output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n    assert_call = [\n        'assert',\n        ['call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size],\n    ]\n    if output_size > 0:\n        assert_call = ['seq', assert_call, returner]\n    o = LLLnode.from_list(\n        assert_call,\n        typ=sig.output_type,\n        location='memory',\n        pos=getpos(stmt_expr),\n        add_gas_estimate=add_gas,\n        annotation='Internal Call: %s' % method_name,\n    )\n    o.gas += sig.gas\n    return o\n", "path": "vyper/parser/self_call.py"}], "after_files": [{"content": "import itertools\n\nfrom vyper.exceptions import (\n    ConstancyViolationException,\n)\nfrom vyper.parser.lll_node import (\n    LLLnode,\n)\nfrom vyper.parser.parser_utils import (\n    getpos,\n    pack_arguments,\n)\nfrom vyper.signatures.function_signature import (\n    FunctionSignature,\n)\nfrom vyper.types import (\n    BaseType,\n    ByteArrayLike,\n    ListType,\n    TupleLike,\n    get_size_of_type,\n    get_static_size_of_type,\n    has_dynamic_data,\n)\n\n\ndef call_lookup_specs(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    method_name = stmt_expr.func.attr\n    expr_args = [Expr(arg, context).lll_node for arg in stmt_expr.args]\n    sig = FunctionSignature.lookup_sig(context.sigs, method_name, expr_args, stmt_expr, context)\n    return method_name, expr_args, sig\n\n\ndef make_call(stmt_expr, context):\n    method_name, _, sig = call_lookup_specs(stmt_expr, context)\n\n    if context.is_constant() and not sig.const:\n        raise ConstancyViolationException(\n            \"May not call non-constant function '%s' within %s.\" % (\n                method_name,\n                context.pp_constancy(),\n            ),\n            getpos(stmt_expr)\n        )\n\n    if sig.private:\n        return call_self_private(stmt_expr, context, sig)\n    else:\n        return call_self_public(stmt_expr, context, sig)\n\n\ndef call_make_placeholder(stmt_expr, context, sig):\n    if sig.output_type is None:\n        return 0, 0, 0\n\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    out_size = get_size_of_type(sig.output_type) * 32\n    returner = output_placeholder\n\n    if not sig.private and isinstance(sig.output_type, ByteArrayLike):\n        returner = output_placeholder + 32\n\n    return output_placeholder, returner, out_size\n\n\ndef call_self_private(stmt_expr, context, sig):\n    # ** Private Call **\n    # Steps:\n    # (x) push current local variables\n    # (x) push arguments\n    # (x) push jumpdest (callback ptr)\n    # (x) jump to label\n    # (x) pop return values\n    # (x) pop local variables\n\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    pre_init = []\n    pop_local_vars = []\n    push_local_vars = []\n    pop_return_values = []\n    push_args = []\n\n    # Push local variables.\n    if context.vars:\n        var_slots = [(v.pos, v.size) for name, v in context.vars.items()]\n        var_slots.sort(key=lambda x: x[0])\n        mem_from, mem_to = var_slots[0][0], var_slots[-1][0] + var_slots[-1][1] * 32\n        push_local_vars = [\n            ['mload', pos] for pos in range(mem_from, mem_to, 32)\n        ]\n        pop_local_vars = [\n            ['mstore', pos, 'pass'] for pos in reversed(range(mem_from, mem_to, 32))\n        ]\n\n    # Push Arguments\n    if expr_args:\n        inargs, inargsize, arg_pos = pack_arguments(\n            sig,\n            expr_args,\n            context,\n            return_placeholder=False,\n            pos=getpos(stmt_expr),\n        )\n        push_args += [inargs]  # copy arguments first, to not mess up the push/pop sequencing.\n\n        static_arg_size = 32 * sum(\n                [get_static_size_of_type(arg.typ)\n                    for arg in expr_args])\n        static_pos = arg_pos + static_arg_size\n        needs_dyn_section = any(\n                [has_dynamic_data(arg.typ)\n                    for arg in expr_args])\n\n        if needs_dyn_section:\n            ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)\n            start_label = ident + '_start'\n            end_label = ident + '_end'\n            i_placeholder = context.new_placeholder(BaseType('uint256'))\n\n            # Calculate copy start position.\n            # Given | static | dynamic | section in memory,\n            # copy backwards so the values are in order on the stack.\n            # We calculate i, the end of the whole encoded part\n            # (i.e. the starting index for copy)\n            # by taking ceil32(len<arg>) + offset<arg> + arg_pos\n            # for the last dynamic argument and arg_pos is the start\n            # the whole argument section.\n            for idx, arg in enumerate(expr_args):\n                if isinstance(arg.typ, ByteArrayLike):\n                    last_idx = idx\n            push_args += [\n                ['with', 'offset', ['mload', arg_pos + last_idx * 32],\n                    ['with', 'len_pos', ['add', arg_pos, 'offset'],\n                        ['with', 'len_value', ['mload', 'len_pos'],\n                            ['mstore', i_placeholder,\n                                ['add', 'len_pos', ['ceil32', 'len_value']]]]]]\n            ]\n            # loop from end of dynamic section to start of dynamic section,\n            # pushing each element onto the stack.\n            push_args += [\n\n                ['label', start_label],\n                ['if', ['lt', ['mload', i_placeholder], static_pos],\n                    ['goto', end_label]],\n                ['mload', ['mload', i_placeholder]],\n                ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i\n                ['goto', start_label],\n                ['label', end_label]\n            ]\n\n        # push static section\n        push_args += [\n            ['mload', pos] for pos in reversed(range(arg_pos, static_pos, 32))\n        ]\n\n    # Jump to function label.\n    jump_to_func = [\n        ['add', ['pc'], 6],  # set callback pointer.\n        ['goto', 'priv_{}'.format(sig.method_id)],\n        ['jumpdest'],\n    ]\n\n    # Pop return values.\n    returner = [0]\n    if sig.output_type:\n        output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n        if output_size > 0:\n            dynamic_offsets = []\n            if isinstance(sig.output_type, (BaseType, ListType)):\n                pop_return_values = [\n                    ['mstore', ['add', output_placeholder, pos], 'pass']\n                    for pos in range(0, output_size, 32)\n                ]\n            elif isinstance(sig.output_type, ByteArrayLike):\n                dynamic_offsets = [(0, sig.output_type)]\n                pop_return_values = [\n                    ['pop', 'pass'],\n                ]\n            elif isinstance(sig.output_type, TupleLike):\n                static_offset = 0\n                pop_return_values = []\n                for out_type in sig.output_type.members:\n                    if isinstance(out_type, ByteArrayLike):\n                        pop_return_values.append(\n                            ['mstore', ['add', output_placeholder, static_offset], 'pass']\n                        )\n                        dynamic_offsets.append(\n                            (['mload', ['add', output_placeholder, static_offset]], out_type)\n                        )\n                    else:\n                        pop_return_values.append(\n                            ['mstore', ['add', output_placeholder, static_offset], 'pass']\n                        )\n                    static_offset += 32\n\n            # append dynamic unpacker.\n            dyn_idx = 0\n            for in_memory_offset, _out_type in dynamic_offsets:\n                ident = \"%d_%d_arg_%d\" % (stmt_expr.lineno, stmt_expr.col_offset, dyn_idx)\n                dyn_idx += 1\n                start_label = 'dyn_unpack_start_' + ident\n                end_label = 'dyn_unpack_end_' + ident\n                i_placeholder = context.new_placeholder(typ=BaseType('uint256'))\n                begin_pos = ['add', output_placeholder, in_memory_offset]\n                # loop until length.\n                o = LLLnode.from_list(\n                    ['seq_unchecked',\n                        ['mstore', begin_pos, 'pass'],  # get len\n                        ['mstore', i_placeholder, 0],\n                        ['label', start_label],\n                        [  # break\n                            'if',\n                            ['ge', ['mload', i_placeholder], ['ceil32', ['mload', begin_pos]]],\n                            ['goto', end_label]\n                        ],\n                        [  # pop into correct memory slot.\n                            'mstore',\n                            ['add', ['add', begin_pos, 32], ['mload', i_placeholder]],\n                            'pass',\n                        ],\n                        # increment i\n                        ['mstore', i_placeholder, ['add', 32, ['mload', i_placeholder]]],\n                        ['goto', start_label],\n                        ['label', end_label]],\n                    typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))\n                pop_return_values.append(o)\n\n    call_body = list(itertools.chain(\n        ['seq_unchecked'],\n        pre_init,\n        push_local_vars,\n        push_args,\n        jump_to_func,\n        pop_return_values,\n        pop_local_vars,\n        [returner],\n    ))\n    # If we have no return, we need to pop off\n    pop_returner_call_body = ['pop', call_body] if sig.output_type is None else call_body\n\n    o = LLLnode.from_list(\n        pop_returner_call_body,\n        typ=sig.output_type,\n        location='memory',\n        pos=getpos(stmt_expr),\n        annotation='Internal Call: %s' % method_name,\n        add_gas_estimate=sig.gas\n    )\n    o.gas += sig.gas\n    return o\n\n\ndef call_self_public(stmt_expr, context, sig):\n    # self.* style call to a public function.\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    add_gas = sig.gas  # gas of call\n    inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr))\n    output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n    assert_call = [\n        'assert',\n        ['call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size],\n    ]\n    if output_size > 0:\n        assert_call = ['seq', assert_call, returner]\n    o = LLLnode.from_list(\n        assert_call,\n        typ=sig.output_type,\n        location='memory',\n        pos=getpos(stmt_expr),\n        add_gas_estimate=add_gas,\n        annotation='Internal Call: %s' % method_name,\n    )\n    o.gas += sig.gas\n    return o\n", "path": "vyper/parser/self_call.py"}]}