VM内部構造

Lambda Cが組み込みシステムで安全である理由

このページでは、Lambda C VMアーキテクチャの技術的深掘りを行い、なぜセーフティクリティカルな組み込みシステムに適しているのかを解説します。


非再帰ディスパッチループ

核心となる安全保証

重要な理解: Lambda CのVMは、スクリプト関数呼び出しにC言語レベルの関数再帰を使用しません。これがナイーブなインタープリタとの根本的な違いです。

スクリプト呼び出しの仕組み

スクリプト関数が別の関数を呼び出す(再帰呼び出しを含む)とき、VMは:

  1. フレーム情報をVMスタックにプッシュ - Cスタックではない
  2. プログラムカウンタを更新 して対象関数にジャンプ
  3. ディスパッチループを継続 - 別のC関数を呼び出すことはない

これにより:

従来のインタープリタとの対比

ナイーブなインタープリタ(危険):

Lambda C(安全):

商用上の意義

このアーキテクチャにより実現されること:


ロード時リンク: O(1) FFIディスパッチ

実行時シンボル解決の問題

従来のスクリプト言語(Lua、Python)は、関数名を呼び出すたびに解決します:

これにより可変で予測不能なFFI呼び出しオーバーヘッドが発生します。

Lambda Cの解決策

FFIリンクはバイトコードロード時に一度だけ行われます:

  1. 登録フェーズ: ホストが文字列名で関数を登録
  2. リンクフェーズ: バイトコードローダーがすべての関数名参照を整数IDに変換
  3. 実行フェーズ: FFI呼び出しは整数ID → 直接テーブルルックアップを使用

結果: 以下に関係なくO(1)の定数時間FFIディスパッチ(約100ns):

なぜこれが重要か

100Hz-10kHzで実行される制御ループにおいて:


型スタック: なぜランタイム型追跡が必要か?

Compactバイトコードのトレードオフ

Lambda Cの4バイト命令フォーマットは、命令に型情報をエンコードしないことで極端なコンパクト性を実現しています。ADD命令はintを加算しているのかdoubleを加算しているのかを指定しません。

型スタックによる解決

VMは、VMスタック上の各値のランタイム型を追跡する並列型スタックを保持します:

重要な洞察: これは組み込み向けに最適化された空間-時間トレードオフです:

性能最適化: 高速整数モード

VMが整数のみの演算を検出すると、以下が可能になります:

これが、インタープリタであるにもかかわらずfib(25)が高速に実行される理由です - ホットループがすべて整数演算だからです。

静的型モード (-Os)

コンパイラの -Os オプションは、型情報を完全に省略したバイトコードを生成します:

lcvmc -Os -oc output.lcbc source.c

技術的効果:

トレードオフ:

これは空間と時間の両方を最適化する選択肢であり、組み込みシステムの厳しい制約に適しています。


Arena Allocator: 意図的にfree()なし

なぜfree()がないのか?

従来のmalloc/freeは以下を引き起こします:

Arena Allocatorの特性

Lambda Cのアロケータは:

組み込みユースケースへの適合

この設計は定期的な制御ループに最適です:

制御ループの反復:
1. ヒープリセット → 新鮮なメモリで開始
2. 一時バッファ割り当て → O(1)高速
3. センサーデータ処理 → フラグメンテーションリスクなし
4. 制御信号出力 → 予測可能なメモリ
5. 次の反復 → ヒープリセット、繰り返し

トレードオフ: 定期的にlcvm_heap_reset()を呼び出す必要があります。これは許容可能です。なぜなら:

Heap Watermark API

Arena Allocatorの制限を補完する機能として、Heap Watermark APIを提供:

size_t mark = lcvm_heap_mark();     // 現在位置を記録
char *buf = lcvm_malloc(64*1024);   // 一時確保
// ... 処理 ...
lcvm_heap_release(mark);            // マーク位置まで一括解放

特性:

これにより、長時間稼働システムでのメモリ効率が大幅に向上します。


4バイト命令: キャッシュ効率

なぜ固定長が重要か

可変長命令セット(x86、Luaバイトコード):

固定4バイト命令:

コンパクトかつ完全

4バイトで提供されるもの:

これで十分なもの:

設計原則: ROM/RAMが希少でCPUサイクルが十分な組み込みシステムでは、命令密度 > 生デコード速度。


決定論的メモリ消費

セーフティクリティカル要件

商用組み込みシステムでは、最悪ケースメモリ消費を証明する必要があります。Lambda Cはこれを可能にします:

合計メモリ = vm_stack_size + vm_garea_size + vm_heap_size

境界の証明

  1. VMスタック: STACKSIZEで決定される最大深度 - スタックオーバーフロー検出がこれを超えないようにする
  2. グローバル領域: バイトコードのグローバル変数宣言に基づきロード時に固定
  3. ヒープ: heap_sizeで境界付けられたArena allocator - 使い果たすと割り当ては明確に失敗

隠れた割り当てなし:

認証上の利点

この決定論性は以下に価値があります:


比較: Lambda CがLua/Pythonと異なる理由

アーキテクチャ哲学

側面Lambda CLuaMicroPython
Cスタック使用定数呼び出し深度で増加呼び出し深度で増加
FFIディスパッチO(1)テーブルルックアップO(1)ハッシュテーブル(キャッシュ後)文字列比較
メモリ割り当てArena(freeなし)マーク・スイープGCマーク・スイープGC
命令フォーマット4バイト固定可変(1-4バイト)可変(1-3バイト)
型追跡型スタック値ごとのタグPyObjectヘッダ

組み込み向け設計

Lambda Cは決定論性と安全性に最適化されたトレードオフを行います:

これが、Lua/Pythonが適さないセーフティクリティカル組み込みシステムに適している理由です。


まとめ: 技術評価

Sグレード: アーキテクチャ

非再帰VMループ: スクリプト呼び出しスタックとCスタックの完全分離。最小限のスタック割り当てでRTOSタスクに安全。

ロード時リンク: O(1) FFIディスパッチが実行時シンボル解決オーバーヘッドを排除。リアルタイム制御アプリケーションを可能にする。

Sグレード: メモリ効率

4バイト命令フォーマット: キャッシュフレンドリーな固定長設計を維持しながら極端なROM効率を達成。

Arena allocator: フラグメンテーションゼロ、O(1)割り当て、決定論的メモリ消費。定期的制御ループに理想的。

Sグレード: 商用適合性

決定論的メモリ境界: コンパイル時に合計メモリ消費が証明可能。安全認証を可能にする。

AOTコンパイル: パース複雑性を開発環境に分離。ランタイムはシンプル、境界付き、検証可能。


次のステップ