Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tests/unit/cli/vyper_json/test_compile_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,13 @@ def test_compile_json(input_json, input_bundle, experimental_codegen):
"object": data["bytecode"],
"opcodes": data["opcodes"],
"sourceMap": data["source_map"],
"symbolMap": data["symbol_map"],
},
"deployedBytecode": {
"object": data["bytecode_runtime"],
"opcodes": data["opcodes_runtime"],
"sourceMap": data["source_map_runtime"],
"symbolMap": data["symbol_map_runtime"],
},
"methodIdentifiers": data["method_identifiers"],
},
Expand Down
44 changes: 44 additions & 0 deletions tests/unit/compiler/test_symbol_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from vyper.compiler import compile_code
from vyper.compiler.settings import Settings


TEST_CODE = """
@internal
def foo(a: uint256) -> uint256:
return a + 1

# force foo to not be inlined
@external
def bar(a: uint256) -> uint256:
return self.foo(a)

@external
def baz(a: uint256) -> uint256:
return self.foo(a + 1)
"""


def test_simple_map():
code = TEST_CODE
output = compile_code(
code,
output_formats=["symbol_map_runtime", "metadata"],
settings=Settings(experimental_codegen=True),
)
meta = output["metadata"]
symbol_map = output["symbol_map_runtime"]
foo_meta_ent = None
assert "function_info" in meta, "missing function info in metadata"
function_infos = meta["function_info"]
assert isinstance(function_infos, dict), "function info is not a dict"
for _, v in function_infos.items():
if v["name"] == "foo" and v["visibility"] == "internal":
foo_meta_ent = v
break
assert foo_meta_ent is not None, "didn't find entry for foo"
assert "venom_via_stack" in foo_meta_ent, "no stack info"
assert foo_meta_ent.get("venom_return_via_stack", False), "unexpected non-stack return"
assert foo_meta_ent["venom_via_stack"] == ["a"]
foo_id = foo_meta_ent["_ir_identifier"]
symbol_map_key = foo_id + "_runtime"
assert symbol_map_key in symbol_map, "missing constant start for foo()"
6 changes: 6 additions & 0 deletions vyper/cli/vyper_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
"evm.bytecode.object": "bytecode",
"evm.bytecode.opcodes": "opcodes",
"evm.bytecode.sourceMap": "source_map",
"evm.bytecode.symbolMap": "symbol_map",
"evm.deployedBytecode.object": "bytecode_runtime",
"evm.deployedBytecode.opcodes": "opcodes_runtime",
"evm.deployedBytecode.sourceMap": "source_map_runtime",
"evm.deployedBytecode.symbolMap": "symbol_map_runtime",
"interface": "interface",
"ir": "ir_dict",
"ir_runtime": "ir_runtime_dict",
Expand Down Expand Up @@ -425,6 +427,8 @@ def format_to_output_dict(compiler_data: dict) -> dict:
evm["opcodes"] = data["opcodes"]
if "source_map" in data:
evm["sourceMap"] = data["source_map"]
if "symbol_map" in data:
evm["symbolMap"] = data["symbol_map"]

if any(i + "_runtime" in data for i in evm_keys + pc_maps_keys):
evm = output_contracts.setdefault("evm", {}).setdefault("deployedBytecode", {})
Expand All @@ -434,6 +438,8 @@ def format_to_output_dict(compiler_data: dict) -> dict:
evm["opcodes"] = data["opcodes_runtime"]
if "source_map_runtime" in data:
evm["sourceMap"] = data["source_map_runtime"]
if "symbol_map_runtime" in data:
evm["symbolMap"] = data["symbol_map_runtime"]

if any(i in data for i in VENOM_KEYS):
venom = {}
Expand Down
2 changes: 2 additions & 0 deletions vyper/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
"blueprint_bytecode": output.build_blueprint_bytecode_output,
"opcodes": output.build_opcodes_output,
"opcodes_runtime": output.build_opcodes_runtime_output,
"symbol_map": output.build_symbol_map,
"symbol_map_runtime": output.buld_symbol_map_runtime,
}

INTERFACE_OUTPUT_FORMATS = [
Expand Down
21 changes: 21 additions & 0 deletions vyper/compiler/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from vyper.semantics.types.function import ContractFunctionT, FunctionVisibility, StateMutability
from vyper.typing import StorageLayout
from vyper.utils import safe_relpath
from vyper.venom.ir_node_to_venom import _pass_via_stack, _returns_word
from vyper.warnings import ContractSizeLimit, vyper_warn


Expand Down Expand Up @@ -265,6 +266,14 @@ def _to_dict(func_t):
ret["source_id"] = func_t.decl_node.module_node.source_id
ret["function_id"] = func_t._function_id

if func_t.is_internal and compiler_data.settings.experimental_codegen:
pass_via_stack = _pass_via_stack(func_t)
pass_via_stack_list = [
arg for (arg, is_stack_arg) in pass_via_stack.items() if is_stack_arg
]
ret["venom_via_stack"] = pass_via_stack_list
ret["venom_return_via_stack"] = _returns_word(func_t)

keep_keys = {
"name",
"return_type",
Expand All @@ -279,6 +288,8 @@ def _to_dict(func_t):
"module_path",
"source_id",
"function_id",
"venom_via_stack",
"venom_return_via_stack",
}
ret = {k: v for k, v in ret.items() if k in keep_keys}
return ret
Expand Down Expand Up @@ -438,6 +449,16 @@ def _compress_source_map(ast_map, jump_map, bytecode_size):
return ";".join(ret)


def build_symbol_map(compiler_data: CompilerData) -> dict:
sym, _, _ = compile_ir.resolve_symbols(compiler_data.assembly)
return {k.label: v for (k, v) in sym.items()}


def buld_symbol_map_runtime(compiler_data: CompilerData) -> dict:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

sym, _, _ = compile_ir.resolve_symbols(compiler_data.assembly_runtime)
return {k.label: v for (k, v) in sym.items()}


def build_bytecode_output(compiler_data: CompilerData) -> str:
return f"0x{compiler_data.bytecode.hex()}"

Expand Down
2 changes: 1 addition & 1 deletion vyper/venom/ir_node_to_venom.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def _append_return_args(fn: IRFunction, ofst: int = 0, size: int = 0):
# func_t: ContractFunctionT
@functools.lru_cache(maxsize=1024)
def _pass_via_stack(func_t) -> dict[str, bool]:
# returns a dict which returns True if a given argument (referered to
# returns a dict which returns True if a given argument (referred to
# by name) should be passed via the stack
if not ENABLE_NEW_CALL_CONV:
return {arg.name: False for arg in func_t.arguments}
Expand Down
Loading