# WasmEdge Executor 執行詳解


## 程式碼

可以看[程式碼](https://github.com/WasmEdge/WasmEdge/blob/99394eb0e53dab489a80b78f6dc93f44d7add690/lib/executor/instantiate/module.cpp#L17)，大概可以看出 Executor 在初始化會做什麼事情。

```cpp
Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> Executor::instantiate(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, std::optional<std::string_view> Name)
```

參數原型如上，可以看到有參數

1. `Runtime::StoreManager &StoreMgr`: 提供導入（Import）時所需的外部實例尋找，並在實例化成功後負責「註冊」該模組。它維護了整個運行時的狀態空間
2. `const AST::Module &Mod`: 靜態藍圖，這是由載入器（Loader）解析並驗證後的抽象語法樹（AST）。包含了 WebAssembly 檔案的所有原始資訊（如指令、段數據、類型定義）。它是唯讀的（const）
3. `std::optional<std::string_view> Name`: 定此模組是否為「具名模組」。若有值，該實例會以該名稱註冊進 StoreMgr，供其他模組後續引用；若無值（std::nullopt），則視為匿名模組

回傳值則是使用 Expect 處理錯誤，並且使用 unique_ptr 保證只有一個獨占此指標，最後回傳一個 `Runtime::Instance::ModuleInstance` 要，這是最終產物。它包含了所有運行時需要的數據結構：跳轉表、動態分配的記憶體快、初始化的全域變數值，以及指向具體執行代碼的指針。

詳細在來看一下函式做了什麼事情。

1. 先用 AST Module 自己的函式檢查模組是否合法
2. 創建 StackManager
3. 檢查 Module 是否有名字，有的話看 StoreMgr 裡面有沒有重複的名字
4. 直接給一個 ModuleInstance
5. 將 AST（靜態藍圖）中的類型定義，複製到 ModInst（動態實例）中。這樣以後在進行函式調用或導入檢查時，實例才能快速查詢類型是否匹配
6. Import Section: 根據導入清單，去 StoreManager 尋找對應的外部函式、記憶體或全域變數並進行連結（Matching）

    ```cpp
    // Instantiate ImportSection and do import matching. (ImportSec)
    const AST::ImportSection &ImportSec = Mod.getImportSection();
    EXPECTED_TRY(instantiate(
                    [&StoreMgr](std::string_view ModName)
                        -> const WasmEdge::Runtime::Instance::ModuleInstance * {
                        return StoreMgr.findModule(ModName);
                    },
                    *ModInst, ImportSec)
                    .map_error(ReportError(ASTNodeAttr::Sec_Import)));

    ```

    可以詳細看下程式碼，基本上他是呼叫重載函式 [instantiate(...)](https://github.com/WasmEdge/WasmEdge/blob/master/lib/executor/instantiate/import.cpp#L113) 在 [lib/executor/instantiate/import.cpp](https://github.com/WasmEdge/WasmEdge/blob/master/lib/executor/instantiate/import.cpp) 裡面。

    第一個參數是一個 lambda 函式，基本上只是他現現在這個 Module 要 import 另外一個 Module，傳入的參數是 `ModName` 也就是那個 Module 的名字，我們就直接在 `StoreMgr` 裡面找給他，最後回傳一個 `ModuleInstance`。

    第二參數就是現在的 `ModInst`，第三個參數則是 `ImportSec`，我們會用 for loop 看裡面一個一個找要 import 誰，這時候就會用到第一個參數的 lambda 函式找東西了。

    最前面的 `EXPECTED_TRY` 巨集，它會執行括號內的函式，如果函式回傳「成功」（Success），它就把結果拿出來，程式繼續往下跑。如果函式回傳「失敗」（Unexpect/Error），它會立刻中斷當前的 `instantiate` 函式，並直接將錯誤往上層丟，也就是後面的 `.map_error()`。
7. 準備一些執行環境，比較特別是，StackMgr 是為了暫時在這邊計算 Wasm Global 變數初始值，因為 Wasm 的 Global 初始值可以是動態計算的（雖然受限），這需要一個運作中的 Stack
8. 最後，假如是具名模組，也就是有 Name，那就在 StoreMgr 註冊

## Import 程式碼

實際我們可以在看 重載函式 [instantiate(...)](https://github.com/WasmEdge/WasmEdge/blob/master/lib/executor/instantiate/import.cpp#L113) 在 [lib/executor/instantiate/import.cpp](https://github.com/WasmEdge/WasmEdge/blob/master/lib/executor/instantiate/import.cpp) 裡面的東西。

可以看到他第一個參數也就是 `ModuleFinder`，我們的 lambda 函式

```cpp
// Instantiate imports. See "include/executor/executor.h".
Expect<void> Executor::instantiate(
    std::function<const Runtime::Instance::ModuleInstance *(std::string_view)>
        ModuleFinder,
    Runtime::Instance::ModuleInstance &ModInst,
    const AST::ImportSection &ImportSec) {

    ...

    const auto *ImpModInst = ModuleFinder(ModName);

```

