7 ポイント 投稿者 GN⁺ 2025-12-24 | 2件のコメント | WhatsAppで共有
  • MicroQuickJS(MQuickJS) は組み込みシステム向けに設計された超軽量 JavaScriptエンジン で、約10kBのRAMと100kBのROMだけで動作可能
  • QuickJSに近い速度 を維持しつつメモリ使用量を減らすため、トレーシングガベージコレクタUTF-8文字列保存方式 を採用
  • 対応言語は ES5に近い制限付きJavaScriptサブセット で、エラーになりやすい構文を禁止する strict mode のみを許可
  • REPLツール mqjs により、スクリプト実行、バイトコード保存、メモリ制限設定が可能で、生成されたバイトコードはROMから直接実行可能
  • エンジン全体と標準ライブラリがROMに常駐し、高速な初期化と低メモリ消費 を実現、組み込み環境での JavaScript実行効率 を高める

紹介

  • MicroQuickJS(MQuickJS) は組み込みシステムを対象とした JavaScriptエンジン で、10kBのRAMと100kBのROM(ARM Thumb-2コードを含む)で動作
    • 速度はQuickJSに近い
  • ES5に近いサブセット のみをサポートし、非効率またはエラーになりやすい構文を禁止 する strict mode でのみ動作
  • QuickJSとコードの一部を共有するが、内部構造は メモリ節約のため完全に異なる設計 になっている
    • トレーシングガベージコレクタCPUスタック不使用UTF-8文字列保存 方式を使用

REPL

  • REPLコマンドは mqjs で、スクリプト実行、評価、インタラクティブモード、メモリ制限設定、バイトコード保存などをサポート
    • 例: ./mqjs --memory-limit 10k tests/mandelbrot.js
  • -o オプションで コンパイル済みバイトコード をファイルに保存可能
    • 保存したバイトコードは ./mqjs mandelbrot.bin で実行可能
  • バイトコードはCPUの エンディアン および ワード長(32/64ビット) によって異なり、-m32 オプションで32ビット向けバイトコードを生成可能
  • --no-column オプションで デバッグ情報の列番号を削除 可能

strict mode

  • strict mode のみ許可され、with キーワードは使用不可、グローバル変数は必ず var で宣言する必要がある
  • 配列のホール(hole) は許可されない
    • 例: a[10] = 2 はTypeErrorを発生させる
    • ホールのある配列が必要な場合は通常のオブジェクトを使用
  • グローバルevalのみ対応 し、ローカル変数へのアクセスは不可
  • 値のボクシング(value boxing) は未対応(new Number(1) など)

JavaScriptサブセット

  • strict mode ベースで、ES5互換性 を重視
  • Arrayオブジェクト にはホールがなく、範囲外インデックスへのアクセスはエラー
  • for in はオブジェクトの 自身のプロパティのみを列挙 し、for of は配列のみサポート
  • グローバルオブジェクト は存在するがgetter/setterは不可、直接作成したプロパティはグローバル変数として公開されない
  • 正規表現(Regexp) はASCIIのみ大文字小文字を区別せず処理し、/./ はUTF-16ではなくユニコードコードポイント単位でマッチ
  • 文字列関数 はASCIIのみ処理(toLowerCase, toUpperCase
  • DateDate.now() のみサポート
  • 追加対応機能:
    • for of, Typed arrays, \u{hex} 文字列リテラル
    • Math関数: imul, clz32, fround, trunc, log2, log10
    • 指数演算子正規表現フラグ(s, y, u)文字列関数(replaceAll, trimStart, trimEnd)、globalThis

C API

  • Cライブラリ依存を最小化 し、malloc, free, printf は未使用
  • メモリバッファを直接提供 する必要があり、エンジンはそのバッファ内でのみメモリを割り当てる
    • 例: ctx = JS_NewContext(mem_buf, sizeof(mem_buf), &js_stdlib)
  • ガベージコレクション方式 により JS_FreeValue() の呼び出しは不要
  • オブジェクトアドレスは割り当てのたびに移動しうるため、JSValue ポインタの使用を推奨
    • JS_PushGCRef() / JS_PopGCRef() で安全に参照管理
  • 標準ライブラリ はROMに保存可能なC構造体としてコンパイルされ、高速な初期化と低RAM使用量 を実現
  • バイトコード実行 はROMから可能で、JS_RelocateBytecode() で再配置した後、JS_LoadBytecode()JS_Run() で実行
  • 数学ライブラリ(libm.c)浮動小数点エミュレータ を内蔵

内部構造とQuickJSとの比較

  • ガベージコレクション: 参照カウントの代わりに トレーシング・コンパクションGC を使用
    • メモリ断片化を防ぎ、オブジェクトサイズを縮小
  • 値表現: CPUのワードサイズ(32/64ビット)に合わせて設計
    • 31ビット整数、ユニコードコードポイント、浮動小数点、メモリブロックポインタを格納可能
  • 文字列はUTF-8で保存 され、QuickJSの8/16ビット配列方式より効率的
  • C関数 は単一値として保存可能で、プロパティ追加は不可
  • 標準ライブラリ はROMに常駐し、RAMオブジェクトを最小化することで 高速なエンジン初期化 が可能
  • バイトコード はスタックベースで、間接参照テーブル により読み取り専用として扱う
    • Golombコード で行番号・列番号を圧縮
  • コンパイラ はQuickJSに近いが、非再帰パーサ を使用してCスタック使用量を抑制
    • 構文木なしで 単一パスのバイトコード生成 を行う

テストとベンチマーク

  • 基本テスト: make test
  • QuickJSマイクロベンチマーク: make microbench
  • Octaneベンチマーク(strict mode向け修正版)は別途ダウンロード可能
    • 実行: make octane

ライセンス

  • MITライセンス で配布
  • ソースコードの著作権は Fabrice BellardCharlie Gordon が保有

2件のコメント

 
xguru 2025-12-24

Fabrice Bellard についての紹介は、以前私がコメントに書いたものを参考にしてください。この方は本当に一貫していて、驚くべき怪物です..
https://news.hada.io/comment?id=51

 
GN⁺ 2025-12-24
Hacker News のコメント
  • 2010年にこれが存在していたら、Redis のスクリプト言語は Lua ではなく JavaScript になっていた気がする
    Lua が選ばれたのは言語的な理由ではなく、実装上の制約(小さい、速い、ANSI-C ベース)によるものだった
    Lua のいくつかのアイデアは良いが、個人的には Algol 系の文法 から外れた点は不要に感じていた
    SmallTalk や FORTH のように、新しい抽象概念を学ぶ代償として生じる混乱には価値があるが、Lua の変化にはそれだけの理由がないと思う

    • Lua の文法が好きというわけではないが、開発者たちがそれを選んだ理由は十分理解できると思う
      Lua は tail call optimization(TCO) をサポートする唯一の軽量言語で、そのおかげでループなしに再帰だけでプログラムを書ける
      JavaScript にはその最適化がないため、同じやり方はできない
      Lua は コンパイラ実装 にも特に向いている。再帰的な構造が多いからだ
      Redis のスクリプティングには JS の方が合っているかもしれないが、Lua をけなすのは残念だ
    • Lua が 1993 年に最初に登場したことを考えると、当時としてはかなり 伝統的な文法 だった
      ブラジルでは C より Pascal や Ada の方が広く使われていたため、その影響を受けたのだろう
      Ruby や Perl も同じくらいの時期に出たが、もっとはるかに急進的な文法の変化を試みていた
    • 最初は 13 歳のときに Lua を簡単に学べたという話を書こうとしてやめたが、コメント投稿者が antirez 本人だと気づいて驚いた
    • 文法の問題は解決しないだろうが、“language skins” という概念は面白い
      パーサーとレキサーを分離しておきながら、{} の代わりに then/end のようなトークンを差し替える試みはほとんど見たことがない
      関連議論: HN スレッド, Reddit の議論
    • Redis のスクリプト言語として Tcl は検討されなかったのか気になる。元祖組み込み言語だからだ
  • このエンジンは、昔 JSC を触っていたときに自分が望んでいたやり方で JS を制限 している
    Web では互換性のためにこうした制約は不可能だが、組み込み環境ではむしろこうした制約が うれしい設計 になり得る

    • すでに、こうした制約のない JS エンジンを持っている
    • JSC で進めていた マルチスレッド対応の作業 がどうなったのか気になる。Apple を離れたあとに中断されたのか、それともコードはまだ残っているのか知りたい
  • ブラウザで MicroQuickJS をそのまま実行できる プレイグラウンド を作った
    MicroQuickJS WebAssembly 版
    参考までに元の QuickJS 版 もある
    QuickJS は 2.28MB、MicroQuickJS は 303KB でずっと軽い

    • ビルドに名前情報などが含まれてサイズが大きくなっているようだ
      emcc -O3 オプションや --closure 1 を追加すればさらに削減できそう
      QuickJS はすでに最適化済みで、MicroQuickJS の方だけ改善余地がある
  • Jeff Atwood の有名な言葉どおり、「JavaScript で書けるあらゆるアプリは、最終的に JavaScript で書かれる」
    いまやその言葉は組み込みシステムにも当てはまるようだ
    Jeff Atwood のウィキ

    • 同感。関連講演: The Birth and Death of JavaScript
    • Fabrice Bellard はブラウザ内で Linux を動かせる JS ベースの VM も作ったことがある
      JSLinux リンク
    • これはほとんどインターネット版の Rule 35 のような感じだ
  • コミット履歴なしでアップロードされたのが惜しい
    このレベルの開発者がどれだけの速さでプロジェクトを仕上げるのか見てみたかった
    どうせ QuickJS ベースなので、比較自体に大きな意味はなさそうだが

    • 「public repository of…」という表現を見ると、実際の作業履歴は非公開リポジトリにある可能性がある
    • あるいは単に 一発で完成 させたのかもしれない
  • これが yt-dlp の YouTube JS チャレンジ を解く最も軽量な方法になり得るのか気になる
    yt-dlp EJS ドキュメント 参照
    QuickJS はすでにサポートされている

    • 可能性は低そうだ。ES5 レベルの 部分実装 しかサポートしていないからだ
      YouTube の JS パズルはあまりに複雑で、Python 製の JS エミュレータですら断念したほどだ
    • ES5 しか実装されていないので、現実的には難しいと思う
  • 組み込みシステムには詳しくないが、こうしたエンジンで ESP32 や Arduino を JavaScript でプログラム できるようになるのか気になる
    MicroPython のようなものだ

    • すでに似たプロジェクトはいくつかある
    • Moddable/Kinoma の XS エンジン は ES6 以上をサポートしている
      MicroQuickJS は ES5 の一部しか実装しておらず、環境バインディングも提供しない
    • Tessel という JS プログラミングボードがあった
      JS コードを Lua VM のバイトコードに変換して実行していて、かなり賢いアプローチだった
      最近、あの古い Node 0.8 CLI を Rust で書き直してみたが、結局ハードウェアは引き出しに戻った
    • 重要なのは malloc() を使わない構造 だという点だ。それが可能性を開く
  • タイミングは本当に重要だ。昨夜投稿したときはまったく反応がなかった

    • たぶん 運の問題 にすぎない
    • 他の人も試したが反応はなかった
      米国の朝の時間帯に再投稿したり、定期的に再掲したりする戦略がある
  • Fabrice Bellard は現存する中でもっとも生産的で多才なプログラマーの一人だ
    代表作: FFmpeg, QEMU, JSLinux, TCC, QuickJS
    伝説的な人物だ

    • 彼が高く評価されている割に、その 開発スタイル に注目する人は少ない
      最小限の依存関係とツールで完全なプログラムを作るアプローチが印象的だ
    • もはや彼は一人の人間ではなく、熟練ハッカー集団のコードネーム なのではないかと思えてくる
      本当に人間なら眠らないといけないはずだから
    • 彼は LLM 推論エンジン も自ら開発していて、GPT-2 の時代から維持している
      ts_server, TextSynth
    • 興味深いのは、彼が作るプログラムの大半が GUI 中心のユーザーインターフェース を扱わないことだ
      ユーザーがパラメータを設定すると、プログラムが完結的に実行される構造を好んでいるように見える
    • 国際難読化 C コードコンテスト(IOCCC) で 3 回優勝した経歴もある
      IOCCC 受賞者一覧
  • 「10kB の RAM でも JS をコンパイルして実行できる」 という点が印象的だ
    今のように RAM が高価になっている時期 にちょうど合っている
    これを Chromium や Electron に組み込めるのか気になる

    • Web 互換性のため難しいだろうが、どうせ Chromium の メモリ削減効果 も大きくはなさそうだ