diff options
| author | Cliff Click <cliffc@acm.org> | 2026-08-10 11:11:18 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-24 15:56:44 -0700 |
| commit | 741d78b6e840c88b7b183010c812ad982b342da1 (patch) | |
| tree | 84a75eb7ad351bffd20cd5fb152bab032b74271c /docs/chapter28a/README.ja.md | |
| parent | 8d90d2292bbdb23596849c3c3d1cda2f6cad783e (diff) | |
| download | Simple-linear-chapter28a.tar.gz Simple-linear-chapter28a.zip | |
Chapter 28a: Modules and Lazy Class Initializationlinear-chapter28a
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com>
Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com>
Co-authored-by: Symious <14933944+symious@users.noreply.github.com>
Co-authored-by: Jun Kawasaki <jun784@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'docs/chapter28a/README.ja.md')
| -rw-r--r-- | docs/chapter28a/README.ja.md | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/docs/chapter28a/README.ja.md b/docs/chapter28a/README.ja.md new file mode 100644 index 00000000..84dcdda2 --- /dev/null +++ b/docs/chapter28a/README.ja.md @@ -0,0 +1,94 @@ +# 第28a章: モジュールと遅延クラス初期化 + +[次の章: 分離コンパイル](../chapter28b/README.ja.md) + +[English](README.md) | 日本語 + +[Previous: Chapter 27](../chapter27/README.ja.md) | +[Next: Chapter 28b](../chapter28b/README.ja.md) + +この章では複数のソースファイルを一度にコンパイルします。各ファイルは +一つのクラスと共有オブジェクトを定義し、トップレベルの文は隠れた +`<clinit>` 関数になります。最初の能動的な使用で初期化し、その後は +同じ結果を使います。クラスへの参照を保持するだけでは初期化しません。 + +## 必要なときだけ表を作る + +実行できる例は [`src/test/smp/lazy`](../../src/test/smp/lazy) にあります。 +`App.smp` は Main、Tables、Stats への参照を公開します。 +`App/Stats.smp` の `builds` は初期化回数を数えます。 +`App/Tables.smp` は次のように表を構築します。 + +```simple +Stats.builds++; +int[] _squares=new int[256]; +for(int i=0; i<256; i++) _squares[i]=i*i; +val square={u8 n -> _squares[n];}; +``` + +`App/Main.smp` が入口です。 + +```simple +return arg ? Tables.square(3)+Tables.square(4)+100*Stats.builds : Stats.builds; +``` + +引数が 0 なら結果は 0 で、Tables は初期化されません。引数が 1 なら +9 + 16 + 100 = 125 です。二度の呼び出しでも表は一度しか作りません。 +`_squares` は非公開のフィールドで、公開関数を通して読み出します。 +完全なファイル一覧と評価用 Java コードは [英語版](README.md) を参照してください。 + +## ファイルと解析の境界 + +`ParseAll` は未解決のクラス名や型から必要なソースを探します。 +ディレクトリ階層が名前空間になり、`App/Main` から `Tables` は兄弟の +`App/Tables` を指せます。親の初期化は子より先なので、親も解析します。 +相互参照する型はソースの発見後に閉じます。 + +`CompUnit` はソース、クラス型、関数をまとめます。各単位には +`StartCU` と `StopCU` があり、全体の Start/Stop の下で解析します。 +公開関数には未知の呼び出し元が存在します。非公開の関数は引き続き +エスケープ解析によって特殊化できます。フィールド名の先頭の `_` は +非公開を表します。ただし、現実装はこれを公開インターフェースの選択に使うだけで、 +兄弟クラスからの直接アクセスをまだ拒否しません。このアクセス検査は未実装です。 + +標準ライブラリ `sys` もソースから解析します。ローカルの `sys` が +なければ `src/main/smp` を使います。ネイティブの `"C"` 宣言は従来通り +ネイティブリンカーで解決します。 + +## 初期化の順序と循環 + +クラスのフィールドの読み書き、メソッド呼び出し、インスタンス生成は +初期化を必要とします。パーサーは `CLInit` を挿入し、最適化中は制御と +メモリ効果を持つ不透明なノードとして残します。実行後は隠れた `$init` +フラグが真なので、通常のメモリ最適化で重複した検査を除去できます。 + +型やクラスへの参照の循環は合法です。しかし A の初期化が B を使い、 +B の初期化が A を使う場合、先に完了できるクラスがありません。 +`ClassInitDependencies` は最適化後の呼び出しと `CLInit` をたどり、 +複数のクラス初期化を含む循環をソース位置付きで報告します。 +通常の再帰や同じ初期化関数内の再帰は許されます。 + +検査後、`Lower` はフラグ検査と未初期化時の呼び出しに展開します。 +親を先に初期化し、フラグは初期化関数の入口で真にします。同じクラスのヘルパーから +再び使えるようにするためです。他クラスを経由して未完成のクラスへ戻る循環は拒否します。 +初期化関数 A が B の初期化を完了させてから再開することは可能です。 + +## コード生成とビルド + +この章では必要なソースをすべて同時にコンパイルします。`FinishCalls` +が解析用の呼び出し辺を切り離し、`StaticData` がクラスの共有領域と +定数フィールドを配置します。ELF は発見したソースのうち生きているコードを含みますが、 +理想 IR のシリアライズ情報は含みません。 + +リポジトリのルートで次を実行します。 + +```sh +make tests CHAPTERS=chapter28a +``` + +このディレクトリでは初回に `make lib`、続いて `make tests` を使えます。 +`make view` は共有グラフビューアーを起動します。 + +次の章ではライブラリのソースがなくてもコンパイルできるように、型と +理想 IR の保存、インポート時の識別子変換、インポート先を含む初期化検査 +を追加します。ライブラリ構築と最適化の調整は付録として扱います。 |
