# EIP-6206 - JUMPF 與非回傳函式

# 注意事項

本文並沒有經過作者外的其他審查者審核,因此若內容有誤,請到 issue 區提出問題,我會儘速修改,謝謝。

# 摘要

本 EIP 是對於 EIP-4750 EOF 函式的擴充,提供尾端呼叫最佳化機制,透過加入了一個新指令 JUMPF,可在不新增回傳堆疊框架的情況下跳轉至其他程式碼區段。

同時也擴充了型別區段的格式,允許標註某個區段為「非回傳區段」,並為跳轉至這類區段的 JUMPF 指令提供簡化的堆疊驗證邏輯。

# 目的

在常見的函式設計中,某些函式在執行結束時只會呼叫另一個函式然後立即回傳。JUMPF 能在不需建立新回傳堆疊框架的情況下,切換至另一個區段執行,進而最佳化這類尾端呼叫行為。

若在驗證階段已能確定某函式永遠不會將控制流程回傳給呼叫端,則使用 JUMPF 時可將其視為終止指令,允許操作數堆疊在執行終止時保留額外資料。這將提供編譯器更多最佳化空間,無論是在程式碼體積或 gas 消耗上皆具優勢。

此特性特別適用於以 REVERT 結尾的錯誤處理輔助函式。這些輔助函式經常在多個分支中重複使用,若無需在 JUMPF 前先移除堆疊上的多餘項目,就能以更有效率的方式進行抽取與重用。

# 實際例子:費波那契數列計算

費波那契數列定義如下:

  • F(0) = 0
  • F(1) = 1
  • F(n) = F(n-1) + F(n-2),當 n > 1

# 傳統方法(使用 CALLF 與 RETF)

區段 0(主程式): PUSH 10 // 計算 F(10) CALLF 1 // 呼叫費波那契函式 STOP // 結束執行

區段 1(fib 函式): DUP1 // 複製 n PUSH 2 LT // n < 2 ? JUMPI base_case // 是的話跳到基本情況

DUP1 PUSH 1 SWAP1 SUB // n-1 CALLF 1 // 呼叫 F(n-1)

SWAP1 PUSH 2 SWAP1 SUB // n-2 CALLF 1 // 呼叫 F(n-2)

ADD // F(n-1) + F(n-2) RETF

base_case: RETF // 回傳 n(F(0) 或 F(1))

# 使用尾端遞迴與 JUMPF 最佳化版本

我們可以將此函式改寫為尾端遞迴形式,並在最後使用 JUMPF

區段 0(主程式,非回傳): PUSH 10 // n PUSH 0 // a = F(0) PUSH 1 // b = F(1) JUMPF 1 // 進入 fibTail 區段

區段 1(fibTail 函式): // Stack: [n, a, b] DUP1 ISZERO JUMPI return_a // 若 n == 0,回傳 a

SWAP1 DUP3 ADD // 計算 a+b SWAP2 PUSH 1 SWAP1 SUB // n-1 SWAP1 SWAP2 // 參數變為 [a+b, n-1, b]

JUMPF 1 // 尾呼叫 fibTail(n-1, b, a+b)

return_a: SWAP1 SWAP2 POP POP RETF

# 執行流程比較

傳統方法:                           使用 JUMPF 優化:
+—————+                  +––––––––+
| CALLF fib(10) |                  | JUMPF fibTail  |
+—————+                  +––––––––+
|                                  |
v                                  v
+—————+                  +––––––––+
| 建立回傳框架   |                  | 無需建立回傳框架 |
+—————+                  +––––––––+
|                                  |
v                                  v
遞迴呼叫                          迭代執行
(堆疊框架增長)                     (不增加堆疊框架)
|                                  |
v                                  v
+—————+                  +––––––––+
| 多次 CALLF/RETF|                  | 多次 JUMPF     |
+—————+                  +––––––––+
|                                  |
v                                  v
+—————+                  +––––––––+
| 回傳堆疊展開   |                  | 當 n=0 時回傳   |
+—————+                  +––––––––+

# 規格

# 型別區段變更

若某區段在執行後永遠不會回傳,則可標記為「非回傳區段」。此類區段的 outputs 欄位在型別區段中設為 0x80

第一個程式碼區段,即 main 程式區段必須為非回傳區段,且不接受任何輸入。

# 執行語意

新增指令:JUMPF (0xe5)

  1. JUMPF 具一個立即參數 target_section_index,為 16 位元無號 big-endian 整數,代表目標的程式碼區段。
  2. 若執行後的堆疊深度超過 1024 - type[target].max_stack_increase,則導致異常終止。
  3. 執行時會將目前區段設為目標區段,PC 設為 0,但不更動回傳堆疊。
  4. 消耗 5 gas。
  5. 不對操作數堆疊進行 pop 或 push 操作。

對於傳統位元組碼,執行 JUMPF 將觸發異常終止。

# 程式碼驗證

對每個 JUMPF

  • target_section_index 必須小於區段總數。
  • 需滿足以下條件之一:
    • type[current].outputstype[target].outputs
    • type[target].outputs == 0x80
  • 若跳轉至非回傳區段,需滿足:stack_height_min >= type[target].inputs
  • 若跳轉至可回傳區段,需滿足:stack_height_min == stack_height_max == type[current].outputs - type[target].outputs + type[target].inputs
  • stack_height_max ≤ 1024 - type[target].max_stack_increase
  • JUMPF 被視為終止指令,不可有後續指令
  • 若任何 RJUMP* 偏移至 JUMPF 的立即參數部分,驗證失敗
  • CALLF 不可呼叫非回傳區段(即 outputs == 0x80

# 非回傳狀態驗證

當且僅當某區段不含 RETF 且僅使用 JUMPF 指向其他非回傳區段時,該區段才可被標記為非回傳。

# 原理

# 為何允許跳轉至輸出較少的區段?

為避免重複程式碼,JUMPF 允許從輸出較多的區段跳轉至輸出較少的區段,只要這些額外的輸出已在目前區段補足。這樣一來,共用的輔助函式就可以通用使用,無需硬性對應輸出數量。

傳統函式模式:                      使用 JUMPF 的優化模式:
+––––+                          +––––+
| 函式 A  |                          | 函式 A  |
+––––+                          +––––+
|                                   |
| CALLF B                           | JUMPF B
|                                   |
v                                   v
+––––+                          +––––+
| 函式 B  |                          | 函式 B  |
+––––+                          +––––+
|                                   |
| RETF                              | (無需回傳)
|                                   |
v                                   |
+––––+                              |
| 函式 A  |                              |
+––––+                              |
|                                   |
| RETF                              |
v                                   v
Last Updated: 2025/5/21 下午3:18:25