We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Immutable variables can be read before assignment
### Version Information

* vyper Version (output of `vyper --version`): 0.3.6+commit.4a2124d
* OS: osx
* Python Version: 3.9.13
 
### What's your issue about?

Immutable variables can be read before assignment, their memory location during constructor execution is accessed, but that memory is not initialized yet. Its value is not necessarily `empty(type)` since memory could have been written to ephemerally.

This should not compile:

```python
# @version 0.3.6

a:immutable(uint256)
b:uint256

@payable
@external
def __init__(s:address):
    self.b = a
    a = 12
```

A more interesting example where transient memory written during execution of `create_copy_of()` is written into the storage variable `b`:

```python
# @version 0.3.6

a:immutable(uint256)
b:uint256

@payable
@external
def __init__():
    s:address = 0x9D0464996170c6B9e75eED71c68B99dDEDf279e8  #random contract containing code that is copied to memory before redeploying
    c:address = create_copy_of(s)
    self.b = a
    a = 12
```

### How can it be fixed?

check that immutable variables are assigned before usage


--- 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/codegen/module.py`
Content:
```
1 # a contract.vy -- all functions and constructor
2 
3 from typing import Any, List, Optional
4 
5 from vyper import ast as vy_ast
6 from vyper.codegen.core import shr
7 from vyper.codegen.function_definitions import FuncIRInfo, generate_ir_for_function
8 from vyper.codegen.global_context import GlobalContext
9 from vyper.codegen.ir_node import IRnode
10 from vyper.exceptions import CompilerPanic
11 
12 
13 def _topsort_helper(functions, lookup):
14     #  single pass to get a global topological sort of functions (so that each
15     # function comes after each of its callees). may have duplicates, which get
16     # filtered out in _topsort()
17 
18     ret = []
19     for f in functions:
20         # called_functions is a list of ContractFunctions, need to map
21         # back to FunctionDefs.
22         callees = [lookup[t.name] for t in f._metadata["type"].called_functions]
23         ret.extend(_topsort_helper(callees, lookup))
24         ret.append(f)
25 
26     return ret
27 
28 
29 def _topsort(functions):
30     lookup = {f.name: f for f in functions}
31     # strip duplicates
32     return list(dict.fromkeys(_topsort_helper(functions, lookup)))
33 
34 
35 def _is_constructor(func_ast):
36     return func_ast._metadata["type"].is_constructor
37 
38 
39 def _is_fallback(func_ast):
40     return func_ast._metadata["type"].is_fallback
41 
42 
43 def _is_internal(func_ast):
44     return func_ast._metadata["type"].is_internal
45 
46 
47 def _is_payable(func_ast):
48     return func_ast._metadata["type"].is_payable
49 
50 
51 # codegen for all runtime functions + callvalue/calldata checks + method selector routines
52 def _runtime_ir(runtime_functions, global_ctx):
53     # categorize the runtime functions because we will organize the runtime
54     # code into the following sections:
55     # payable functions, nonpayable functions, fallback function, internal_functions
56     internal_functions = [f for f in runtime_functions if _is_internal(f)]
57 
58     external_functions = [f for f in runtime_functions if not _is_internal(f)]
59     default_function = next((f for f in external_functions if _is_fallback(f)), None)
60 
61     # functions that need to go exposed in the selector section
62     regular_functions = [f for f in external_functions if not _is_fallback(f)]
63     payables = [f for f in regular_functions if _is_payable(f)]
64     nonpayables = [f for f in regular_functions if not _is_payable(f)]
65 
66     # create a map of the IR functions since they might live in both
67     # runtime and deploy code (if init function calls them)
68     internal_functions_ir: list[IRnode] = []
69 
70     for func_ast in internal_functions:
71         func_ir = generate_ir_for_function(func_ast, global_ctx, False)
72         internal_functions_ir.append(func_ir)
73 
74     # for some reason, somebody may want to deploy a contract with no
75     # external functions, or more likely, a "pure data" contract which
76     # contains immutables
77     if len(external_functions) == 0:
78         # TODO: prune internal functions in this case? dead code eliminator
79         # might not eliminate them, since internal function jumpdest is at the
80         # first instruction in the contract.
81         runtime = ["seq"] + internal_functions_ir
82         return runtime
83 
84     # note: if the user does not provide one, the default fallback function
85     # reverts anyway. so it does not hurt to batch the payable check.
86     default_is_nonpayable = default_function is None or not _is_payable(default_function)
87 
88     # when a contract has a nonpayable default function,
89     # we can do a single check for all nonpayable functions
90     batch_payable_check = len(nonpayables) > 0 and default_is_nonpayable
91     skip_nonpayable_check = batch_payable_check
92 
93     selector_section = ["seq"]
94 
95     for func_ast in payables:
96         func_ir = generate_ir_for_function(func_ast, global_ctx, False)
97         selector_section.append(func_ir)
98 
99     if batch_payable_check:
100         selector_section.append(["assert", ["iszero", "callvalue"]])
101 
102     for func_ast in nonpayables:
103         func_ir = generate_ir_for_function(func_ast, global_ctx, skip_nonpayable_check)
104         selector_section.append(func_ir)
105 
106     if default_function:
107         fallback_ir = generate_ir_for_function(default_function, global_ctx, skip_nonpayable_check)
108     else:
109         fallback_ir = IRnode.from_list(
110             ["revert", 0, 0], annotation="Default function", error_msg="fallback function"
111         )
112 
113     # ensure the external jumptable section gets closed out
114     # (for basic block hygiene and also for zksync interpreter)
115     # NOTE: this jump gets optimized out in assembly since the
116     # fallback label is the immediate next instruction,
117     close_selector_section = ["goto", "fallback"]
118 
119     runtime = [
120         "seq",
121         ["with", "_calldata_method_id", shr(224, ["calldataload", 0]), selector_section],
122         close_selector_section,
123         ["label", "fallback", ["var_list"], fallback_ir],
124     ]
125 
126     # note: dead code eliminator will clean dead functions
127     runtime.extend(internal_functions_ir)
128 
129     return runtime
130 
131 
132 # take a GlobalContext, and generate the runtime and deploy IR
133 def generate_ir_for_module(global_ctx: GlobalContext) -> tuple[IRnode, IRnode]:
134     # order functions so that each function comes after all of its callees
135     function_defs = _topsort(global_ctx.functions)
136 
137     init_function: Optional[vy_ast.FunctionDef] = None
138 
139     # generate all FuncIRInfos
140     for f in function_defs:
141         func_t = f._metadata["type"]
142         func_t._ir_info = FuncIRInfo(func_t)
143 
144     runtime_functions = [f for f in function_defs if not _is_constructor(f)]
145     init_function = next((f for f in function_defs if _is_constructor(f)), None)
146 
147     runtime = _runtime_ir(runtime_functions, global_ctx)
148 
149     deploy_code: List[Any] = ["seq"]
150     immutables_len = global_ctx.immutable_section_bytes
151     if init_function:
152         # TODO might be cleaner to separate this into an _init_ir helper func
153         init_func_ir = generate_ir_for_function(
154             init_function, global_ctx, skip_nonpayable_check=False, is_ctor_context=True
155         )
156         deploy_code.append(init_func_ir)
157 
158         # pass the amount of memory allocated for the init function
159         # so that deployment does not clobber while preparing immutables
160         # note: (deploy mem_ofst, code, extra_padding)
161         init_mem_used = init_function._metadata["type"]._ir_info.frame_info.mem_used
162         deploy_code.append(["deploy", init_mem_used, runtime, immutables_len])
163 
164         # internal functions come after everything else
165         internal_functions = [f for f in runtime_functions if _is_internal(f)]
166         for f in internal_functions:
167             func_ir = generate_ir_for_function(
168                 f, global_ctx, skip_nonpayable_check=False, is_ctor_context=True
169             )
170             # note: we depend on dead code eliminator to clean dead function defs
171             deploy_code.append(func_ir)
172 
173     else:
174         if immutables_len != 0:
175             raise CompilerPanic("unreachable")
176         deploy_code.append(["deploy", 0, runtime, 0])
177 
178     return IRnode.from_list(deploy_code), IRnode.from_list(runtime)
179
```
--- 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/codegen/module.py b/vyper/codegen/module.py
--- a/vyper/codegen/module.py
+++ b/vyper/codegen/module.py
@@ -153,12 +153,31 @@
         init_func_ir = generate_ir_for_function(
             init_function, global_ctx, skip_nonpayable_check=False, is_ctor_context=True
         )
-        deploy_code.append(init_func_ir)
 
         # pass the amount of memory allocated for the init function
         # so that deployment does not clobber while preparing immutables
         # note: (deploy mem_ofst, code, extra_padding)
         init_mem_used = init_function._metadata["type"]._ir_info.frame_info.mem_used
+
+        # force msize to be initialized past the end of immutables section
+        # so that builtins which use `msize` for "dynamic" memory
+        # allocation do not clobber uninitialized immutables.
+        # cf. GH issue 3101.
+        # note mload/iload X touches bytes from X to X+32, and msize rounds up
+        # to the nearest 32, so `iload`ing `immutables_len - 32` guarantees
+        # that `msize` will refer to a memory location of at least
+        # `<immutables_start> + immutables_len` (where <immutables_start> ==
+        # `_mem_deploy_end` as defined in the assembler).
+        # note:
+        #   mload 32 => msize == 64
+        #   mload 33 => msize == 96
+        # assumption in general: (mload X) => msize == ceil32(X + 32)
+        # see py-evm extend_memory: after_size = ceil32(start_position + size)
+        if immutables_len > 0:
+            deploy_code.append(["iload", max(0, immutables_len - 32)])
+
+        deploy_code.append(init_func_ir)
+
         deploy_code.append(["deploy", init_mem_used, runtime, immutables_len])
 
         # internal functions come after everything else

{"golden_diff": "diff --git a/vyper/codegen/module.py b/vyper/codegen/module.py\n--- a/vyper/codegen/module.py\n+++ b/vyper/codegen/module.py\n@@ -153,12 +153,31 @@\n         init_func_ir = generate_ir_for_function(\n             init_function, global_ctx, skip_nonpayable_check=False, is_ctor_context=True\n         )\n-        deploy_code.append(init_func_ir)\n \n         # pass the amount of memory allocated for the init function\n         # so that deployment does not clobber while preparing immutables\n         # note: (deploy mem_ofst, code, extra_padding)\n         init_mem_used = init_function._metadata[\"type\"]._ir_info.frame_info.mem_used\n+\n+        # force msize to be initialized past the end of immutables section\n+        # so that builtins which use `msize` for \"dynamic\" memory\n+        # allocation do not clobber uninitialized immutables.\n+        # cf. GH issue 3101.\n+        # note mload/iload X touches bytes from X to X+32, and msize rounds up\n+        # to the nearest 32, so `iload`ing `immutables_len - 32` guarantees\n+        # that `msize` will refer to a memory location of at least\n+        # `<immutables_start> + immutables_len` (where <immutables_start> ==\n+        # `_mem_deploy_end` as defined in the assembler).\n+        # note:\n+        #   mload 32 => msize == 64\n+        #   mload 33 => msize == 96\n+        # assumption in general: (mload X) => msize == ceil32(X + 32)\n+        # see py-evm extend_memory: after_size = ceil32(start_position + size)\n+        if immutables_len > 0:\n+            deploy_code.append([\"iload\", max(0, immutables_len - 32)])\n+\n+        deploy_code.append(init_func_ir)\n+\n         deploy_code.append([\"deploy\", init_mem_used, runtime, immutables_len])\n \n         # internal functions come after everything else\n", "issue": "Immutable variables can be read before assignment\n### Version Information\r\n\r\n* vyper Version (output of `vyper --version`): 0.3.6+commit.4a2124d\r\n* OS: osx\r\n* Python Version: 3.9.13\r\n \r\n### What's your issue about?\r\n\r\nImmutable variables can be read before assignment, their memory location during constructor execution is accessed, but that memory is not initialized yet. Its value is not necessarily `empty(type)` since memory could have been written to ephemerally.\r\n\r\nThis should not compile:\r\n\r\n```python\r\n# @version 0.3.6\r\n\r\na:immutable(uint256)\r\nb:uint256\r\n\r\n@payable\r\n@external\r\ndef __init__(s:address):\r\n    self.b = a\r\n    a = 12\r\n```\r\n\r\nA more interesting example where transient memory written during execution of `create_copy_of()` is written into the storage variable `b`:\r\n\r\n```python\r\n# @version 0.3.6\r\n\r\na:immutable(uint256)\r\nb:uint256\r\n\r\n@payable\r\n@external\r\ndef __init__():\r\n    s:address = 0x9D0464996170c6B9e75eED71c68B99dDEDf279e8  #random contract containing code that is copied to memory before redeploying\r\n    c:address = create_copy_of(s)\r\n    self.b = a\r\n    a = 12\r\n```\r\n\r\n### How can it be fixed?\r\n\r\ncheck that immutable variables are assigned before usage\r\n\n", "before_files": [{"content": "# a contract.vy -- all functions and constructor\n\nfrom typing import Any, List, Optional\n\nfrom vyper import ast as vy_ast\nfrom vyper.codegen.core import shr\nfrom vyper.codegen.function_definitions import FuncIRInfo, generate_ir_for_function\nfrom vyper.codegen.global_context import GlobalContext\nfrom vyper.codegen.ir_node import IRnode\nfrom vyper.exceptions import CompilerPanic\n\n\ndef _topsort_helper(functions, lookup):\n    #  single pass to get a global topological sort of functions (so that each\n    # function comes after each of its callees). may have duplicates, which get\n    # filtered out in _topsort()\n\n    ret = []\n    for f in functions:\n        # called_functions is a list of ContractFunctions, need to map\n        # back to FunctionDefs.\n        callees = [lookup[t.name] for t in f._metadata[\"type\"].called_functions]\n        ret.extend(_topsort_helper(callees, lookup))\n        ret.append(f)\n\n    return ret\n\n\ndef _topsort(functions):\n    lookup = {f.name: f for f in functions}\n    # strip duplicates\n    return list(dict.fromkeys(_topsort_helper(functions, lookup)))\n\n\ndef _is_constructor(func_ast):\n    return func_ast._metadata[\"type\"].is_constructor\n\n\ndef _is_fallback(func_ast):\n    return func_ast._metadata[\"type\"].is_fallback\n\n\ndef _is_internal(func_ast):\n    return func_ast._metadata[\"type\"].is_internal\n\n\ndef _is_payable(func_ast):\n    return func_ast._metadata[\"type\"].is_payable\n\n\n# codegen for all runtime functions + callvalue/calldata checks + method selector routines\ndef _runtime_ir(runtime_functions, global_ctx):\n    # categorize the runtime functions because we will organize the runtime\n    # code into the following sections:\n    # payable functions, nonpayable functions, fallback function, internal_functions\n    internal_functions = [f for f in runtime_functions if _is_internal(f)]\n\n    external_functions = [f for f in runtime_functions if not _is_internal(f)]\n    default_function = next((f for f in external_functions if _is_fallback(f)), None)\n\n    # functions that need to go exposed in the selector section\n    regular_functions = [f for f in external_functions if not _is_fallback(f)]\n    payables = [f for f in regular_functions if _is_payable(f)]\n    nonpayables = [f for f in regular_functions if not _is_payable(f)]\n\n    # create a map of the IR functions since they might live in both\n    # runtime and deploy code (if init function calls them)\n    internal_functions_ir: list[IRnode] = []\n\n    for func_ast in internal_functions:\n        func_ir = generate_ir_for_function(func_ast, global_ctx, False)\n        internal_functions_ir.append(func_ir)\n\n    # for some reason, somebody may want to deploy a contract with no\n    # external functions, or more likely, a \"pure data\" contract which\n    # contains immutables\n    if len(external_functions) == 0:\n        # TODO: prune internal functions in this case? dead code eliminator\n        # might not eliminate them, since internal function jumpdest is at the\n        # first instruction in the contract.\n        runtime = [\"seq\"] + internal_functions_ir\n        return runtime\n\n    # note: if the user does not provide one, the default fallback function\n    # reverts anyway. so it does not hurt to batch the payable check.\n    default_is_nonpayable = default_function is None or not _is_payable(default_function)\n\n    # when a contract has a nonpayable default function,\n    # we can do a single check for all nonpayable functions\n    batch_payable_check = len(nonpayables) > 0 and default_is_nonpayable\n    skip_nonpayable_check = batch_payable_check\n\n    selector_section = [\"seq\"]\n\n    for func_ast in payables:\n        func_ir = generate_ir_for_function(func_ast, global_ctx, False)\n        selector_section.append(func_ir)\n\n    if batch_payable_check:\n        selector_section.append([\"assert\", [\"iszero\", \"callvalue\"]])\n\n    for func_ast in nonpayables:\n        func_ir = generate_ir_for_function(func_ast, global_ctx, skip_nonpayable_check)\n        selector_section.append(func_ir)\n\n    if default_function:\n        fallback_ir = generate_ir_for_function(default_function, global_ctx, skip_nonpayable_check)\n    else:\n        fallback_ir = IRnode.from_list(\n            [\"revert\", 0, 0], annotation=\"Default function\", error_msg=\"fallback function\"\n        )\n\n    # ensure the external jumptable section gets closed out\n    # (for basic block hygiene and also for zksync interpreter)\n    # NOTE: this jump gets optimized out in assembly since the\n    # fallback label is the immediate next instruction,\n    close_selector_section = [\"goto\", \"fallback\"]\n\n    runtime = [\n        \"seq\",\n        [\"with\", \"_calldata_method_id\", shr(224, [\"calldataload\", 0]), selector_section],\n        close_selector_section,\n        [\"label\", \"fallback\", [\"var_list\"], fallback_ir],\n    ]\n\n    # note: dead code eliminator will clean dead functions\n    runtime.extend(internal_functions_ir)\n\n    return runtime\n\n\n# take a GlobalContext, and generate the runtime and deploy IR\ndef generate_ir_for_module(global_ctx: GlobalContext) -> tuple[IRnode, IRnode]:\n    # order functions so that each function comes after all of its callees\n    function_defs = _topsort(global_ctx.functions)\n\n    init_function: Optional[vy_ast.FunctionDef] = None\n\n    # generate all FuncIRInfos\n    for f in function_defs:\n        func_t = f._metadata[\"type\"]\n        func_t._ir_info = FuncIRInfo(func_t)\n\n    runtime_functions = [f for f in function_defs if not _is_constructor(f)]\n    init_function = next((f for f in function_defs if _is_constructor(f)), None)\n\n    runtime = _runtime_ir(runtime_functions, global_ctx)\n\n    deploy_code: List[Any] = [\"seq\"]\n    immutables_len = global_ctx.immutable_section_bytes\n    if init_function:\n        # TODO might be cleaner to separate this into an _init_ir helper func\n        init_func_ir = generate_ir_for_function(\n            init_function, global_ctx, skip_nonpayable_check=False, is_ctor_context=True\n        )\n        deploy_code.append(init_func_ir)\n\n        # pass the amount of memory allocated for the init function\n        # so that deployment does not clobber while preparing immutables\n        # note: (deploy mem_ofst, code, extra_padding)\n        init_mem_used = init_function._metadata[\"type\"]._ir_info.frame_info.mem_used\n        deploy_code.append([\"deploy\", init_mem_used, runtime, immutables_len])\n\n        # internal functions come after everything else\n        internal_functions = [f for f in runtime_functions if _is_internal(f)]\n        for f in internal_functions:\n            func_ir = generate_ir_for_function(\n                f, global_ctx, skip_nonpayable_check=False, is_ctor_context=True\n            )\n            # note: we depend on dead code eliminator to clean dead function defs\n            deploy_code.append(func_ir)\n\n    else:\n        if immutables_len != 0:\n            raise CompilerPanic(\"unreachable\")\n        deploy_code.append([\"deploy\", 0, runtime, 0])\n\n    return IRnode.from_list(deploy_code), IRnode.from_list(runtime)\n", "path": "vyper/codegen/module.py"}], "after_files": [{"content": "# a contract.vy -- all functions and constructor\n\nfrom typing import Any, List, Optional\n\nfrom vyper import ast as vy_ast\nfrom vyper.codegen.core import shr\nfrom vyper.codegen.function_definitions import FuncIRInfo, generate_ir_for_function\nfrom vyper.codegen.global_context import GlobalContext\nfrom vyper.codegen.ir_node import IRnode\nfrom vyper.exceptions import CompilerPanic\n\n\ndef _topsort_helper(functions, lookup):\n    #  single pass to get a global topological sort of functions (so that each\n    # function comes after each of its callees). may have duplicates, which get\n    # filtered out in _topsort()\n\n    ret = []\n    for f in functions:\n        # called_functions is a list of ContractFunctions, need to map\n        # back to FunctionDefs.\n        callees = [lookup[t.name] for t in f._metadata[\"type\"].called_functions]\n        ret.extend(_topsort_helper(callees, lookup))\n        ret.append(f)\n\n    return ret\n\n\ndef _topsort(functions):\n    lookup = {f.name: f for f in functions}\n    # strip duplicates\n    return list(dict.fromkeys(_topsort_helper(functions, lookup)))\n\n\ndef _is_constructor(func_ast):\n    return func_ast._metadata[\"type\"].is_constructor\n\n\ndef _is_fallback(func_ast):\n    return func_ast._metadata[\"type\"].is_fallback\n\n\ndef _is_internal(func_ast):\n    return func_ast._metadata[\"type\"].is_internal\n\n\ndef _is_payable(func_ast):\n    return func_ast._metadata[\"type\"].is_payable\n\n\n# codegen for all runtime functions + callvalue/calldata checks + method selector routines\ndef _runtime_ir(runtime_functions, global_ctx):\n    # categorize the runtime functions because we will organize the runtime\n    # code into the following sections:\n    # payable functions, nonpayable functions, fallback function, internal_functions\n    internal_functions = [f for f in runtime_functions if _is_internal(f)]\n\n    external_functions = [f for f in runtime_functions if not _is_internal(f)]\n    default_function = next((f for f in external_functions if _is_fallback(f)), None)\n\n    # functions that need to go exposed in the selector section\n    regular_functions = [f for f in external_functions if not _is_fallback(f)]\n    payables = [f for f in regular_functions if _is_payable(f)]\n    nonpayables = [f for f in regular_functions if not _is_payable(f)]\n\n    # create a map of the IR functions since they might live in both\n    # runtime and deploy code (if init function calls them)\n    internal_functions_ir: list[IRnode] = []\n\n    for func_ast in internal_functions:\n        func_ir = generate_ir_for_function(func_ast, global_ctx, False)\n        internal_functions_ir.append(func_ir)\n\n    # for some reason, somebody may want to deploy a contract with no\n    # external functions, or more likely, a \"pure data\" contract which\n    # contains immutables\n    if len(external_functions) == 0:\n        # TODO: prune internal functions in this case? dead code eliminator\n        # might not eliminate them, since internal function jumpdest is at the\n        # first instruction in the contract.\n        runtime = [\"seq\"] + internal_functions_ir\n        return runtime\n\n    # note: if the user does not provide one, the default fallback function\n    # reverts anyway. so it does not hurt to batch the payable check.\n    default_is_nonpayable = default_function is None or not _is_payable(default_function)\n\n    # when a contract has a nonpayable default function,\n    # we can do a single check for all nonpayable functions\n    batch_payable_check = len(nonpayables) > 0 and default_is_nonpayable\n    skip_nonpayable_check = batch_payable_check\n\n    selector_section = [\"seq\"]\n\n    for func_ast in payables:\n        func_ir = generate_ir_for_function(func_ast, global_ctx, False)\n        selector_section.append(func_ir)\n\n    if batch_payable_check:\n        selector_section.append([\"assert\", [\"iszero\", \"callvalue\"]])\n\n    for func_ast in nonpayables:\n        func_ir = generate_ir_for_function(func_ast, global_ctx, skip_nonpayable_check)\n        selector_section.append(func_ir)\n\n    if default_function:\n        fallback_ir = generate_ir_for_function(default_function, global_ctx, skip_nonpayable_check)\n    else:\n        fallback_ir = IRnode.from_list(\n            [\"revert\", 0, 0], annotation=\"Default function\", error_msg=\"fallback function\"\n        )\n\n    # ensure the external jumptable section gets closed out\n    # (for basic block hygiene and also for zksync interpreter)\n    # NOTE: this jump gets optimized out in assembly since the\n    # fallback label is the immediate next instruction,\n    close_selector_section = [\"goto\", \"fallback\"]\n\n    runtime = [\n        \"seq\",\n        [\"with\", \"_calldata_method_id\", shr(224, [\"calldataload\", 0]), selector_section],\n        close_selector_section,\n        [\"label\", \"fallback\", [\"var_list\"], fallback_ir],\n    ]\n\n    # note: dead code eliminator will clean dead functions\n    runtime.extend(internal_functions_ir)\n\n    return runtime\n\n\n# take a GlobalContext, and generate the runtime and deploy IR\ndef generate_ir_for_module(global_ctx: GlobalContext) -> tuple[IRnode, IRnode]:\n    # order functions so that each function comes after all of its callees\n    function_defs = _topsort(global_ctx.functions)\n\n    init_function: Optional[vy_ast.FunctionDef] = None\n\n    # generate all FuncIRInfos\n    for f in function_defs:\n        func_t = f._metadata[\"type\"]\n        func_t._ir_info = FuncIRInfo(func_t)\n\n    runtime_functions = [f for f in function_defs if not _is_constructor(f)]\n    init_function = next((f for f in function_defs if _is_constructor(f)), None)\n\n    runtime = _runtime_ir(runtime_functions, global_ctx)\n\n    deploy_code: List[Any] = [\"seq\"]\n    immutables_len = global_ctx.immutable_section_bytes\n    if init_function:\n        # TODO might be cleaner to separate this into an _init_ir helper func\n        init_func_ir = generate_ir_for_function(\n            init_function, global_ctx, skip_nonpayable_check=False, is_ctor_context=True\n        )\n\n        # pass the amount of memory allocated for the init function\n        # so that deployment does not clobber while preparing immutables\n        # note: (deploy mem_ofst, code, extra_padding)\n        init_mem_used = init_function._metadata[\"type\"]._ir_info.frame_info.mem_used\n\n        # force msize to be initialized past the end of immutables section\n        # so that builtins which use `msize` for \"dynamic\" memory\n        # allocation do not clobber uninitialized immutables.\n        # cf. GH issue 3101.\n        # note mload/iload X touches bytes from X to X+32, and msize rounds up\n        # to the nearest 32, so `iload`ing `immutables_len - 32` guarantees\n        # that `msize` will refer to a memory location of at least\n        # `<immutables_start> + immutables_len` (where <immutables_start> ==\n        # `_mem_deploy_end` as defined in the assembler).\n        # note:\n        #   mload 32 => msize == 64\n        #   mload 33 => msize == 96\n        # assumption in general: (mload X) => msize == ceil32(X + 32)\n        # see py-evm extend_memory: after_size = ceil32(start_position + size)\n        if immutables_len > 0:\n            deploy_code.append([\"iload\", max(0, immutables_len - 32)])\n\n        deploy_code.append(init_func_ir)\n\n        deploy_code.append([\"deploy\", init_mem_used, runtime, immutables_len])\n\n        # internal functions come after everything else\n        internal_functions = [f for f in runtime_functions if _is_internal(f)]\n        for f in internal_functions:\n            func_ir = generate_ir_for_function(\n                f, global_ctx, skip_nonpayable_check=False, is_ctor_context=True\n            )\n            # note: we depend on dead code eliminator to clean dead function defs\n            deploy_code.append(func_ir)\n\n    else:\n        if immutables_len != 0:\n            raise CompilerPanic(\"unreachable\")\n        deploy_code.append([\"deploy\", 0, runtime, 0])\n\n    return IRnode.from_list(deploy_code), IRnode.from_list(runtime)\n", "path": "vyper/codegen/module.py"}]}