制約と上限
YanmaJS が対応しない機能・実装上の制限・利用上の注意、エンジンの上限値をまとめます。
非目標の機能
- YanmaJSはES2026にほぼ準拠していますが、YanmaJSの思想・用途から意図的に非目標として対応しない機能があります
- 非目標の機能はtest262(ECMAScript 準拠テストスイート)でもskip対象としています
Intl
Intl は日付・数値の書式や文字列の並び順を各言語・地域の慣習に合わせるための API 群(国際化 API)で、コア言語仕様(ECMA-262)とは別の標準(ECMA-402)として定義されている。エンジンは ECMA-402 を実装しなくても ECMA-262 準拠を名乗れる
- 実装には全言語ぶんの月名・曜日名・数値書式・並び順規則などのデータベース(ICU/CLDR)が必要で、そのデータだけで数十 MB — 軽量エンジン本体より桁違いに大きく、「小さく組み込める」という本エンジンの存在意義と両立しない
localeCompare / toLocale* 系のメソッド自体は存在し、ロケール非依存の合理的な動作をする(ECMA-262 はこれを implementation-defined として許容しており、仕様適合のまま)
- 各言語向けの書式が必要なアプリケーションは、ホスト(ネイティブ)側の国際化ライブラリで整形して結果を JS に渡せばよい
IANA タイムゾーン・非 ISO カレンダー
Asia/Tokyo のような地名タイムゾーンは IANA が管理する外部データベースの識別子で、各地の夏時間の歴史や制度変更を含むため年に数回更新される — 同梱すると更新を永久に追従し続ける義務を負う
- ECMA-262 自体が要求するのは UTC と固定オフセット(
+09:00 等)のみで、地名タイムゾーンと和暦などの非 ISO カレンダーは ECMA-402 側の義務。Intl と同じ理由で非目標(指定すると RangeError)
- 時刻の計算は UTC・固定オフセットで完結でき、地名 → オフセットの変換が必要な場合は OS のタイムゾーン機能を使ってホスト側で行える
マルチエージェント共有メモリ
- 複数の worker(実行スレッド)が同じ
SharedArrayBuffer のメモリを同時に読み書きする、ブラウザ向けに後付けされた例外的な仕組み。JavaScript は本来シングルスレッドの言語
- これを実装するにはエンジン内部(GC・アロケータ)全体をスレッドセーフにする必要があり、複雑さと性能低下の代償が大きい
- ECMAScript 仕様は「エージェント(実行スレッド)が 1 つだけのホスト」を明示的に認めており、本エンジンは単一エージェント・ホストとして完全適合(
SharedArrayBuffer/Atomics の API 自体は実装済み)
- 並行実行が必要な場合は、ホストがスレッドごとに独立した VM を立ててメッセージパッシングで連携する(本エンジンは複数 VM の並行動作を保証済み)
WebAssembly 実行
- WebAssembly は JavaScript とは別の言語・別の仮想マシンで、
WebAssembly グローバル API は「JS コードから wasm バイナリをロードして実行する」ためのブラウザ由来の入口。W3C の仕様であって ECMA-262 の一部ではなく、実装しなくても ECMAScript 準拠に影響しない
- 実装するということは、バリデータ・実行エンジン・メモリモデルを備えた第二の VM を丸ごとエンジンに同梱することを意味する
- wasm が必要なホストは、専用の wasm ランタイム(WAMR / wasmtime 等)を並置して C ABI のホスト関数でブリッジするのが業界の定石で、本エンジンでも同じ構成が組める
- なお、エンジン自体を wasm ターゲットにビルドする
yanmajs_wasm は「JS エンジンを wasm 上で動かす」逆方向の話で、こちらは対応している
- 帰結として Source Phase Imports(
import source)の全ターゲットは Source Text Module Record となり、仕様どおり常に SyntaxError になる
Import Assertions
- JSON などを import する際の注釈構文として一時期
assert {} が提案・先行実装されたが、設計上の問題から with {}(Import Attributes)に作り直され、旧構文は標準から削除された
- 現行仕様に存在せず、test262 のテストも全削除済みのため、「実装する対象」がそもそも存在しない(後継の
with {} は対応済み)
Decorators
- 適用プロトコルが未実装(こちらは非目標ではなく標準化待ち)
@decorator はクラスやメソッドに後付けの加工を宣言する構文で、TypeScript などで広く使われているが、JavaScript 標準としてはまだ策定途中(Stage 3)。過去に 2 度全面的に設計が変わった経緯があり、今実装すると手戻りのリスクが大きい
- 現実のデコレータ利用はトランスパイラ(TypeScript/Babel)が変換してからエンジンに届くのが一般的なため、エンジン側の未実装が実害になりにくい
- 構文としては受理する(パースエラーにはならない)が、実行時の適用と auto-accessor の脱糖は未実装。標準化(Stage 4)到達後に実装を検討する
正規表現の制限
- named capture の構文検証(重複名の早期
SyntaxError 検出)は先頭 128 個までが対象
- 129 個目以降もマッチ実行(
groups への反映)は正しく行われる
- ただし 129 個目以降の名前が重複していても、構文解析時には検出されない
- キャプチャグループ数などの固定上限は「エンジンの上限値」の表を参照
文字列の制限
- ロケール依存の動作は簡略化されている(Intl 非目標のため)
localeCompare は NFC 正規化後のコード単位順比較(照合順序は考慮されない)
toLocaleLowerCase / toLocaleUpperCase は toLowerCase / toUpperCase と同一
- 言語別ケーシング(トルコ語の
i/İ 等)には対応しない
- 文字列は内部的に CESU-8 で保持される
length や索引系メソッドは UTF-16 コード単位(仕様準拠)で動作する
- ホストが
toString() で取得するバイト列は CESU-8(astral 文字は 3+3 バイトのサロゲートペア)
makeString(ホスト API)は UTF-8 → CESU-8 を自動正規化する
モジュールシステムの制限
import source は WebAssembly 非対応のため常に SyntaxError(上表参照)
%AbstractModuleSource% は test262 の $262 経由でのみ観測可能
関数・オブジェクトの制限
- sloppy モード関数の
Function.prototype.arguments(実行中の呼び出しに紐づく arguments object を返す Annex B の legacy 挙動)は per-invocation 追跡をせず、常に null を返す
- strict/制限付き関数の
.caller / .arguments は仕様どおり TypeError を投げる
利用上の注意
- Promise の実行モデル:
.then / .catch / .finally のコールバックはジョブ境界まで実行されない(仕様準拠)
- ホスト側は
eval / callFunction / fireTimer の後に drainMicrotasks を呼ぶこと
- Sloppy mode: sloppy 固有のエッジケースで仕様と異なる動作をする場合がある
$262 ハーネス: --test262-harness フラグ付きでのみ提供
agent(マルチスレッド)はスタブで、呼ぶと TypeError を投げる
- ビルド時の機能トグル: 主要機能は
engine_config.zig の comptime フラグで個別に無効化できる
- 無効化した機能に依存するコードは実行時エラーになる
エンジンの上限値
各種上限値は comptime 定数で、実行時には変更できません(GC 設定を除く)。
VM スタック・フレーム
| 項目 |
上限 |
超過時の動作 |
定義箇所 |
| コールスタック深度 |
64 フレーム |
error.CallStackOverflow(Zig エラー) |
vm.zig frames: [64]CallFrame |
| オペランドスタック |
16,384 スロット |
error.StackOverflow(Zig エラー) |
vm.zig stack: [16384]Value |
| try/catch ネスト |
16 段 |
error.TryStackOverflow(Zig エラー) |
vm.zig try_frames: [16]TryFrame |
with スコープネスト |
8 段 |
error.StackOverflow(Zig エラー) |
vm.zig with_scopes: [8]Value |
eval 再帰深度 |
16 段 |
JS RangeError "Maximum eval depth exceeded" |
vm.zig eval_depth: u8 |
注意: コールスタック・オペランドスタック・try スタックの超過は Zig レベルの error として返され、JavaScript の try/catch では捕捉できません。ホスト側で EvalError として受け取る必要があります。eval 深度と正規表現マッチャ再帰深度の超過のみ JS の RangeError として throw されます。
コンパイラ制限
| 項目 |
上限 |
超過時の動作 |
定義箇所 |
| ローカル変数数(関数あたり) |
256 |
SyntaxError "Script too complex (compiler limit exceeded)" |
compiler.zig MAX_LOCALS = 256 |
| アップバリュー数(クロージャあたり) |
256 |
SyntaxError "Too many closure variables" |
compiler.zig MAX_UPVALUES = 256 |
| 定数プール(関数あたり) |
65,535 エントリ |
error.TooManyConstants |
chunk.zig maxInt(u16) |
| ジャンプ距離 |
65,535 バイト |
error.JumpTooLarge |
compiler.zig maxInt(u16) |
| 分割代入パラメータ数 |
8 |
SyntaxError "Script too complex (compiler limit exceeded)" |
compiler.zig MAX_DESTR_PARAMS = 8 |
配列
| 項目 |
上限 |
超過時の動作 |
| 配列の最大インデックス |
4,294,967,294(2^32 - 2) |
RangeError "Invalid array length" |
| 配列の最大長 |
4,294,967,295(2^32 - 1) |
RangeError "Invalid array length" |
正規表現
| 項目 |
上限 |
超過時の動作 |
| キャプチャグループ数 |
1024(named も同上限に従属) |
SyntaxError(構文解析時に検出) |
| 重複 named の早期検出対象 |
先頭 128 個 |
129 個目以降の重複名は構文解析時に検出されない(上記「正規表現の制限」参照) |
| マッチャ再帰深度 |
2,800 |
JS RangeError "regular expression recursion limit exceeded"(捕捉可能) |
| 単純アトム量指定子のバックトラック長 |
2,000 |
上限を超えた古いバックトラック位置はリングバッファで上書きされる(再帰深度とは独立の上限) |
文字列・オブジェクト
| 項目 |
上限 |
| 文字列長 |
メモリ上限まで(固定上限なし) |
| オブジェクトプロパティ数 |
メモリ上限まで(固定上限なし) |
BigInt 桁数 |
メモリ上限まで(任意精度) |
GC 設定(実行時変更可能)
| パラメータ |
デフォルト値 |
説明 |
initial_threshold |
256 オブジェクト |
初回 GC 実行までのオブジェクト数 |
growth_factor |
2 |
GC 後に閾値を 生存オブジェクト数 × growth_factor に設定 |
min_threshold |
256 オブジェクト |
閾値の下限 |
GC は gc_object_count > gc_threshold になったタイミングで自動実行されます。Context.setGCConfig で実行時に変更でき、Context.initWithMemoryLimit で総メモリ使用量に上限を設けられます。