Skip to content

Commit

Permalink
perf: lazy eval of f-strings in IRnode ctor (#3602)
Browse files Browse the repository at this point in the history
25% of IR generation is in IRnode.__repr__ due to the references to self
in the f-strings for panic messages. this commit switches to using
`assert`, which accomplishes the same thing, but lazily evaluating the
error messages (and the code is slightly less pretty)
  • Loading branch information
charles-cooper authored Nov 21, 2023
1 parent 98f502b commit 28b1121
Showing 1 changed file with 42 additions and 53 deletions.
95 changes: 42 additions & 53 deletions vyper/codegen/ir_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,27 +202,23 @@ def __init__(
self.encoding = encoding
self.as_hex = AS_HEX_DEFAULT

def _check(condition, err):
if not condition:
raise CompilerPanic(str(err))

_check(self.value is not None, "None is not allowed as IRnode value")
assert self.value is not None, "None is not allowed as IRnode value"

# Determine this node's valency (1 if it pushes a value on the stack,
# 0 otherwise) and checks to make sure the number and valencies of
# children are correct. Also, find an upper bound on gas consumption
# Numbers
if isinstance(self.value, int):
_check(len(self.args) == 0, "int can't have arguments")
assert len(self.args) == 0, "int can't have arguments"

# integers must be in the range (MIN_INT256, MAX_UINT256)
_check(-(2**255) <= self.value < 2**256, "out of range")
assert -(2**255) <= self.value < 2**256, "out of range"

self.valency = 1
self._gas = 5
elif isinstance(self.value, bytes):
# a literal bytes value, probably inside a "data" node.
_check(len(self.args) == 0, "bytes can't have arguments")
assert len(self.args) == 0, "bytes can't have arguments"

self.valency = 0
self._gas = 0
Expand All @@ -232,10 +228,9 @@ def _check(condition, err):
if self.value.upper() in get_ir_opcodes():
_, ins, outs, gas = get_ir_opcodes()[self.value.upper()]
self.valency = outs
_check(
len(self.args) == ins,
f"Number of arguments mismatched: {self.value} {self.args}",
)
assert (
len(self.args) == ins
), f"Number of arguments mismatched: {self.value} {self.args}"
# We add 2 per stack height at push time and take it back
# at pop time; this makes `break` easier to handle
self._gas = gas + 2 * (outs - ins)
Expand All @@ -244,10 +239,10 @@ def _check(condition, err):
# consumed for internal functions, therefore we whitelist this as a zero valency
# allowed argument.
zero_valency_whitelist = {"pass", "pop"}
_check(
arg.valency == 1 or arg.value in zero_valency_whitelist,
f"invalid argument to `{self.value}`: {arg}",
)
assert (
arg.valency == 1 or arg.value in zero_valency_whitelist
), f"invalid argument to `{self.value}`: {arg}"

self._gas += arg.gas
# Dynamic gas cost: 8 gas for each byte of logging data
if self.value.upper()[0:3] == "LOG" and isinstance(self.args[1].value, int):
Expand Down Expand Up @@ -275,44 +270,40 @@ def _check(condition, err):
self._gas = self.args[0].gas + max(self.args[1].gas, self.args[2].gas) + 3
if len(self.args) == 2:
self._gas = self.args[0].gas + self.args[1].gas + 17
_check(
self.args[0].valency > 0,
f"zerovalent argument as a test to an if statement: {self.args[0]}",
)
_check(len(self.args) in (2, 3), "if statement can only have 2 or 3 arguments")
assert (
self.args[0].valency > 0
), f"zerovalent argument as a test to an if statement: {self.args[0]}"
assert len(self.args) in (2, 3), "if statement can only have 2 or 3 arguments"
self.valency = self.args[1].valency
# With statements: with <var> <initial> <statement>
elif self.value == "with":
_check(len(self.args) == 3, self)
_check(
len(self.args[0].args) == 0 and isinstance(self.args[0].value, str),
f"first argument to with statement must be a variable name: {self.args[0]}",
)
_check(
self.args[1].valency == 1 or self.args[1].value == "pass",
f"zerovalent argument to with statement: {self.args[1]}",
)
assert len(self.args) == 3, self
assert len(self.args[0].args) == 0 and isinstance(
self.args[0].value, str
), f"first argument to with statement must be a variable name: {self.args[0]}"
assert (
self.args[1].valency == 1 or self.args[1].value == "pass"
), f"zerovalent argument to with statement: {self.args[1]}"
self.valency = self.args[2].valency
self._gas = sum([arg.gas for arg in self.args]) + 5
# Repeat statements: repeat <index_name> <startval> <rounds> <rounds_bound> <body>
elif self.value == "repeat":
_check(
len(self.args) == 5, "repeat(index_name, startval, rounds, rounds_bound, body)"
)
assert (
len(self.args) == 5
), "repeat(index_name, startval, rounds, rounds_bound, body)"

counter_ptr = self.args[0]
start = self.args[1]
repeat_count = self.args[2]
repeat_bound = self.args[3]
body = self.args[4]

_check(
isinstance(repeat_bound.value, int) and repeat_bound.value > 0,
f"repeat bound must be a compile-time positive integer: {self.args[2]}",
)
_check(repeat_count.valency == 1, repeat_count)
_check(counter_ptr.valency == 1, counter_ptr)
_check(start.valency == 1, start)
assert (
isinstance(repeat_bound.value, int) and repeat_bound.value > 0
), f"repeat bound must be a compile-time positive integer: {self.args[2]}"
assert repeat_count.valency == 1, repeat_count
assert counter_ptr.valency == 1, counter_ptr
assert start.valency == 1, start

self.valency = 0

Expand All @@ -335,19 +326,17 @@ def _check(condition, err):
# then JUMP to my_label.
elif self.value in ("goto", "exit_to"):
for arg in self.args:
_check(
arg.valency == 1 or arg.value == "pass",
f"zerovalent argument to goto {arg}",
)
assert (
arg.valency == 1 or arg.value == "pass"
), f"zerovalent argument to goto {arg}"

self.valency = 0
self._gas = sum([arg.gas for arg in self.args])
elif self.value == "label":
_check(
self.args[1].value == "var_list",
f"2nd argument to label must be var_list, {self}",
)
_check(len(args) == 3, f"label should have 3 args but has {len(args)}, {self}")
assert (
self.args[1].value == "var_list"
), f"2nd argument to label must be var_list, {self}"
assert len(args) == 3, f"label should have 3 args but has {len(args)}, {self}"
self.valency = 0
self._gas = 1 + sum(t.gas for t in self.args)
elif self.value == "unique_symbol":
Expand All @@ -371,14 +360,14 @@ def _check(condition, err):
# Multi statements: multi <expr> <expr> ...
elif self.value == "multi":
for arg in self.args:
_check(
arg.valency > 0, f"Multi expects all children to not be zerovalent: {arg}"
)
assert (
arg.valency > 0
), f"Multi expects all children to not be zerovalent: {arg}"
self.valency = sum([arg.valency for arg in self.args])
self._gas = sum([arg.gas for arg in self.args])
elif self.value == "deploy":
self.valency = 0
_check(len(self.args) == 3, f"`deploy` should have three args {self}")
assert len(self.args) == 3, f"`deploy` should have three args {self}"
self._gas = NullAttractor() # unknown
# Stack variables
else:
Expand Down

0 comments on commit 28b1121

Please sign in to comment.