diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index 3a09bbe6c0..a09cbde399 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -5,6 +5,8 @@ from vyper import ast as vy_ast from vyper.codegen import external_call, self_call from vyper.codegen.core import ( + _freshname, + add_ofst, append_dyn_array, check_assign, clamp, @@ -154,21 +156,32 @@ def _parse_bytes(self): def _make_bytelike(self, btype, bytez, bytez_length): placeholder = self.context.new_internal_variable(btype) - seq = [] - seq.append(["mstore", placeholder, bytez_length]) - for i in range(0, len(bytez), 32): - seq.append( - [ - "mstore", - ["add", placeholder, i + 32], - bytes_to_int((bytez + b"\x00" * 31)[i : i + 32]), - ] - ) + ret = ["seq"] + assert isinstance(bytez, bytes) + # NOTE: addl opportunities for optimization: + # - intern repeated bytestrings + # - instantiate into memory lazily, pass around bytestring + # literals in IR + # - + length = len(bytez) + if length <= 32: + # in this case, a single mstore is cheaper than + # codecopy. + bytes_as_int = bytes_to_int(bytez) # PUSH data + # bytes are left justified. "Hello" gets written to the + # first 6 bytes of the data buffer of the bytestring + dst = add_ofst(placeholder, length) + ret.append(["mstore", dst, bytes_as_int]) + else: + # codecopy + label = _freshname("bytesdata") + ret.append(["data", label, bytez]) + ret.append(["codecopy", add_ofst(placeholder, 32), ["symbol", label], length]) + # write out the length + ret.append(["mstore", placeholder, length]) + ret.append(placeholder) return IRnode.from_list( - ["seq"] + seq + [placeholder], - typ=btype, - location=MEMORY, - annotation=f"Create {btype}: {bytez}", + ret, typ=btype, location=MEMORY, annotation=f"Create {btype}: {repr(bytez)}" ) # True, False, None constants diff --git a/vyper/utils.py b/vyper/utils.py index db50626713..d74a8b5f11 100644 --- a/vyper/utils.py +++ b/vyper/utils.py @@ -330,10 +330,7 @@ def hex_to_int(inp): # Converts bytes to an integer def bytes_to_int(bytez): - o = 0 - for b in bytez: - o = o * 256 + b - return o + return int.from_bytes(bytez, "big") def is_checksum_encoded(addr):