中抜き
Goコンパイラーは現在Cで書かれています。
コンテキスト
gc "GoツールチェーンはPlan 9コンパイラツールチェーンに由来します。アセンブラ、Cコンパイラ、リンカは基本的に変更されていません。Goコンパイラは、ツールチェーンと一緒に書かれた新しいCプログラムです。
プロジェクト開始当初、GoではなくCでコンパイラを書くことには多くの利点がありました。例えば、第一に、当時Goはコンパイラを書くために存在していませんでした。実際、Goが存在したとしても、互換性のない大きな変更が行われることがよくありました。Goを使わずにCを使えば、初期開発や継続的な開発による問題は避けられたでしょう。しかし現在では、Go 1は安定しており、このような継続的な問題はかなり軽減されています。
継続的な開発の問題は解消され、コンパイラのGo実装をCよりも魅力的なものにするために、別の工学的問題が発生しました:
- 正しいGoのコードを書くのは、正しいCのコードを書くより簡単です。
- バグだらけのGoコードをデバッグするのは、バグだらけのCコードをデバッグするよりも簡単です。
- Goコンパイラーを使うには、Goをある程度理解している必要があります。また、Cコンパイラーを使用するには、C言語をある程度理解している必要があります。
- GoはC言語よりも並行実行が簡単です。
- Goはモジュール性、自動書き換え、ユニットテスト、パフォーマンス分析をサポートする優れた標準を持っています。
- GoCよりは面白いですから。
このような理由から、私はGoコンパイラーをGoで書く時が来たと考えています。
計画シナリオ
第三段階。おそらくgofixとGo oracleのツールを使って、コンパイラをパッケージに分割し、コードをクリーンアップして文書化し、適切なユニットテストを追加します。これが、コンパイラが本物のGoプログラムになるところです。現在のところ、Go 1.4で実装される予定です。
フェーズ IVa.標準的な解析およびテストツールを使用して、コンパイラのCPUおよびメモリ使用量を最適化します。並列処理を導入する必要があるかもしれません。その場合、Race Detector (Goの並列競合検出ツール) が大いに役立ちます。これはGo 1.4を目標にしていますが、1.5まで部分的に遅れるかもしれません。基本的な最適化解析はフェーズ3で行います。
フェーズIVb。コンパイラがパッケージを明確な境界に従って分割した後、構造に依存しない非順序ツリーと構造に依存する順序リストの間に中間コードを明示的に導入する必要があります。この中間コードは全体的なアーキテクチャから独立している必要がありますが、冗長なnil検出やout-of-bounds検出のクリーンアップなど、逐次的だが構造に依存しない処理を最適化するために使用できる正確な実行順序情報を含んでいる必要があります。これらの処理はSSAに基づいています。SSAについてはAlan Donovanのgo.tools/ssaパッケージで学ぶことができます。
自己拡張
Go言語で実装されたGo用コンパイラーは、自己拡張の方法を最初から考慮しなければなりません。考慮すべきルールは、Go 1.3コンパイラーはGo 1.2でコンパイルしなければならない、Go 1.4コンパイラーはGo 1.4でコンパイルしなければならない、などです。
Go1.2ツールチェインをコンパイルし、それを使ってGo1.3ツールチェインをコンパイルする、といった具合です。ここでは、CPU時間だけが消費され、誰かの時間が消費されないようにするために、これを実行するスクリプトが必要です。Go1.xツールチェーンはローカルに保存され、all.bashがGo1.toolchainをコンパイルするときに再び使われます。
明らかに、このブートストラップ・アプローチでは時間が経つにつれて十分ではなくなります。何度もリリースを繰り返すうちに、Cコードを生成するコンパイラのバックエンドを書く方が理にかなっているかもしれません。このCコードは効率的である必要も、読みやすいものである必要もありません。このCコードは、yaccが生成するy.tab.cファイルのようにチェックインされます。このように、自己拡張プロセスは、まずCコードをgccでコンパイルして自己拡張コンパイラを生成し、次にこの自己拡張コンパイラを使って実際のコンパイラをコンパイルするというものになります。他の自己展開プロセスと同様に、この自己展開コンパイラはローカルに保持され、all.bashが実行されるたびに再利用されます。
オルタナティブ
また、より明白な代替案もいくつかあり、それらがなぜ放棄されたのかを説明する必要があります。
最初からコンパイラを書きましょう。最近のコンパイラには、「動く」という非常に重要な特徴があります。Go言語のシンプルさにもかかわらず、コンパイラには細かい最適化や書き換えがたくさんあります。
既存のコンパイラを手放してgccgoを使う 既存のコンパイラは、Go言語の柔軟性を感じさせる重要な部分です。大量のコードに基づくGCCやLLVMを使ってGoアプリケーションを開発しようとすると、Go言語の柔軟性を妨げるように感じます。加えて、GCCは多くのCコードを含むプログラムであり、LLVMは多くのC++コードを含むプログラムです。既存のコンパイル・フレームワークを使わない理由として上に挙げたことは、もっと多くの似たようなライブラリに当てはまります。
C言語の長期使用
最終的に、この計画はPlan9のツールチェーンの一部もC言語で書かれたままにしました。長い目で見れば、コードツリーからすべてのCを除外する方がよいでしょう。この章では、これがどのように起こるかについて少し推測していますが、それが起こることを指定したり、このルーチンに従って起こるという保証はありません。
ランタイム・パッケージ。 ランタイムパッケージのほとんどはCで書かれており、同じ理由でGoコンパイラもCで実装されています。しかし、ランタイムパッケージはコンパイラよりもはるかに小さく、GoとCの混合で書かれています。CコードをGoコードに変換する場合、いくつかの部分を一度に変換することが可能なようです。主な部分は、スケジューラ、ゴミ収集、ハッシュ・マッピング・テーブルの実装、チャネルの実装です。
Cコンパイラ。 プラン9のCコンパイラはそれ自体がCで書かれています。Goパッケージの実装からすべてのCコードが削除されると、これらのコンパイルツールも削除されます: "go tool 6c "など。C を使用しているサードパーティのパッケージがそのような C コードの使用を削除する時間があるように、この計画は事前に宣言されるべきです。 Go1 互換性ドキュメントにはツールチェインの変更に関する記述がありません。
アセンブラ。 Plan 9のアセンブラもCで実装されていますが、このアセンブラは一連のパースツリーからなる単純なパーサーにすぎません。





