> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# JIT 编译

> 通过编译为机器代码实现 EVM 字节码的高性能执行。

## 概要

尽快执行每个 EVM 合约调用直至完成是 Monad 整体性能的关键部分。为此,Monad 同时使用高度优化的解释器和定制的原生代码编译器。编译器一次分析常用合约并缓存原生代码,以便后续调用更高效地执行,同时保留精确的 EVM 语义(包括 gas 和错误行为)。

## 解释 vs. 编译

大多数以太坊客户端每次执行一条智能合约代码指令,在应用指令语义之前检查栈边界和可用 gas。这就是 *解释器*。解释器构建和维护简单,启动延迟低,并且当使用现代技术实现时可以表现得非常好。

另一种方法是 *编译* 程序。在执行开始之前,代码被分析并转换为更高效执行的表示形式。编译增加了前期延迟和复杂性,但每个合约版本只发生一次。如果重复执行更快,整体系统性能就会提高。

为了简单性和可移植性,许多编译器针对更高级别的 *中间表示*(例如 [LLVM IR](https://llvm.org/) 或 [Cranelift](https://cranelift.dev/))。因为 Monad 客户端针对特定的硬件配置,编译器直接生成原生 [x86-64](https://en.wikipedia.org/wiki/X86_assembly_language),以最大化控制和性能,同时仍然精确匹配 EVM 行为。

## 消除冗余工作

编译使我们能够提前预计算行为。考虑这个直线代码片段:

```text theme={null}
JUMPDEST
PUSH1 0x1
ADD
PUSH0
JUMP
```

一旦执行到达 `JUMPDEST`,它必须依次经过 `PUSH1`、`ADD`、`PUSH0` 和 `JUMP`。纯解释器会为每个执行的指令收取 gas 并进行检查。编译器可以识别直线块,并对该块的组合成本执行一次前期 gas 检查(受 EVM 规则约束),然后生成运行该块的代码,而无需每条指令的记账。结果是较少的 CPU 指令,同时保持相同的 gas 计算和 out-of-gas 语义。

[常量折叠](https://en.wikipedia.org/wiki/Constant_folding)是另一个例子。给定:

```text theme={null}
PUSH1 0x2
PUSH1 0x3
ADD
```

编译器可以确定 ADD 处的栈状态并将其折叠为:

```text theme={null}
PUSH1 0x5
```

内部处理,同时仍然收取与原始序列相同的总 gas,并保持 256 位模块化算术语义。

## 优化代码

除了消除冗余工作,编译器还根据操作数所在位置选择高效的实现。它维护一个 *模拟 EVM 栈*,将每个 256 位栈字映射到机器上的一个位置:主内存、一组通用整数寄存器,或一个 AVX 向量寄存器。这种方法结合了传统优化编译器中的[寄存器分配](https://en.wikipedia.org/wiki/Register_allocation)和编译基于栈的语言的[栈缓存](https://dl.acm.org/doi/abs/10.1145/223428.207165)技术。

然后,每个 EVM 指令针对其看到的操作数位置进行专门化。例如,当两个参数都已在 AVX 寄存器中时,`AND` 可以用单个 [x86 `vpand`](https://www.felixcloutier.com/x86/pand) 实现。编译器的大部分有效性来自于为常见的操作数-位置组合发出专门的序列。

## 编译性能

提前编译每个合约是不切实际的。相反,编译器跟踪合约在所有执行中累积消耗的 gas,并为"最热"的合约缓存原生代码。随着区块执行,新变热的合约进入编译队列。编译异步运行,尚未编译(或从未变热)的合约继续在高度优化的解释器上运行。缓存确保对流行合约的重复调用受益于编译,而不会因编译延迟而阻塞执行。
