-
-
Notifications
You must be signed in to change notification settings - Fork 805
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this commit replaces the existing linear entry point search with an O(1) implementation. there are two methods depending on whether optimizing for code size or gas, hash table with probing and perfect hashing using a two-level technique. the first method divides the selectors into buckets, uses `method_id % n_buckets` as a "guess" to where to enter the selector table and then jumps there and performs the familiar linear search for the selector ("probing"). to avoid too large buckets, the jumptable generator searches a range from ~`n_buckets * 0.85` to `n_buckets * 1.15` to minimize worst-case probe depth; the average worst case for 80-100 methods is 3 items per bucket and the worst worst case is 4 items per bucket (presumably if you get really unlucky), see `_bench_sparse()` in `vyper/codegen/jumptable_utils.py`. the average bucket size is 1.6 methods. the second method uses a perfect hashing technique. finding a single magic which produces a perfect hash is infeasible for large `N` (exponential, and in practice seems to run off a cliff around 10 methods). to "get around" this, the methods are divided into buckets of roughly size 10, and a magic is computed per bucket. several `n_buckets` are tried, trying to minimize `n_buckets`. the code size overhead of each bucket is roughly 5 bytes per bucket, which works out to ~20% per method, see `_bench_dense()` in `vyper/codegen/jumptable_utils.py`. then, the function selector is looked up in two steps - it loads the magic for the bucket given by `method_id % n_buckets`, and then uses the magic to compute the location of the function selector (and associated metadata) in the data section. from there it loads the function metadata, performs the calldatasize, callvalue and method id checks and jumps into the function. there is a gas vs code size tradeoff between the two methods - roughly speaking, the sparse method requires ~69 gas in the best case (~109 gas in the "average" case) and 12-22 bytes of code per method, while the dense method requires ~212 gas across the board, and ~8 bytes of code per method. to accomplish this implementation-wise, the jumptable info is generated in a new helper module, `vyper/codegen/jumptable_utils.py`. some refactoring had to be additionally done to pull the calldatasize, callvalue and method id checks from external function generation out into a new selector section construction step in `vyper/codegen/module.py`. additionally, a new IR "data" directive was added, and an associated assembly directive. the data segments in assembly are moved to the end of the bytecode to ensure that data bytes which happen to look like `PUSH` instructions do not mangle valid bytecode which comes after the data section.
- Loading branch information
1 parent
4ca1c81
commit 408929f
Showing
24 changed files
with
1,133 additions
and
230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# prevent module name collision between tests/compiler/test_pre_parser.py | ||
# and tests/ast/test_pre_parser.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from vyper.codegen import core | ||
from vyper.compiler.phases import CompilerData | ||
from vyper.compiler.settings import OptimizationLevel, _is_debug_mode | ||
|
||
|
||
def test_default_settings(): | ||
source_code = "" | ||
compiler_data = CompilerData(source_code) | ||
_ = compiler_data.vyper_module # force settings to be computed | ||
|
||
assert compiler_data.settings.optimize == OptimizationLevel.GAS | ||
|
||
|
||
def test_default_opt_level(): | ||
assert OptimizationLevel.default() == OptimizationLevel.GAS | ||
|
||
|
||
def test_codegen_opt_level(): | ||
assert core._opt_level == OptimizationLevel.GAS | ||
assert core._opt_gas() is True | ||
assert core._opt_none() is False | ||
assert core._opt_codesize() is False | ||
|
||
|
||
def test_debug_mode(pytestconfig): | ||
debug_mode = pytestconfig.getoption("enable_compiler_debug_mode") | ||
assert _is_debug_mode() == debug_mode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.