源映射

作为 AST 输出的一部分,编译器提供了表示 AST 中相应节点的源代码范围。这可用于各种目的,从基于 AST 报告错误的静态分析工具到突出显示局部变量及其使用情况的调试工具。

此外,编译器还可以生成一个从字节码到生成该指令的源代码范围的映射。这再次对于在字节码级别运行的静态分析工具,以及在调试器中显示源代码中的当前位置或处理断点来说很重要。此映射还包含其他信息,如跳转类型和修饰符深度(见下文)。

两种源映射都使用整数标识符来引用源文件。源文件的标识符存储在 output['sources'][sourceName]['id'] 中,其中 output 是标准 JSON 编译器接口输出,解析为 JSON。对于一些实用程序例程,编译器会生成“内部”源文件,这些文件不是原始输入的一部分,但会被源映射引用。这些源文件及其标识符可以通过 output['contracts'][sourceName][contractName]['evm']['bytecode']['generatedSources'] 获取。

注意

对于与任何特定源文件无关的指令,源映射会分配一个整数标识符 -1。这可能发生在源于编译器生成的内联汇编语句的字节码部分中。

AST 中的源映射使用以下符号

s:l:f

其中 s 是源文件中范围开始处的字节偏移量,l 是源范围的长度(以字节为单位),f 是上面提到的源索引。

字节码中源映射的编码更加复杂:它是一个由 ; 分隔的 s:l:f:j:m 列表。这些元素中的每一个都对应于一条指令,即你不能使用字节偏移量,而是必须使用指令偏移量(push 指令的长度超过单个字节)。字段 slf 与上面相同。 j 可以是 io-,分别表示跳转指令是进入函数、从函数返回还是作为循环等的一部分的常规跳转。最后一个字段 m 是一个整数,表示“修饰符深度”。每当进入修饰符中的占位符语句 (_) 时,此深度就会增加;当离开占位符语句时,此深度就会减少。这允许调试器跟踪诸如同一个修饰符使用两次或单个修饰符中使用多个占位符语句等棘手情况。

为了压缩这些源映射,尤其是字节码的源映射,使用了以下规则

  • 如果一个字段为空,则使用前一个元素的值。

  • 如果缺少一个 :,则所有后面的字段都将被视为为空。

这意味着以下源映射表示相同的信息

1:2:1;1:9:1;2:1:2;2:1:2;2:1:2

1:2:1;:9;2:1:2;;

需要注意的是,当使用 verbatim 内置函数时,源映射将无效:内置函数被视为单个指令,而不是潜在的多个指令。