[インデックス 1450] ファイルの概要
このコミットは、Goコンパイラ(6gおよびgc)における内部型表現のクリーンアップを目的としています。具体的には、TMAP(マップ)、TCHAN(チャネル)、TSTRING(文字列)といった型が、常にポインタとして扱われるTPTRラッパーを介して表現されていたのを廃止し、これらの型を直接扱うように変更しています。これにより、コンパイラのコードが簡素化され、型の扱いが一貫性を持つようになります。
コミット
commit a91af04c06e306e87f9b8e2efda41a32ffd75476
Author: Russ Cox <rsc@golang.org>
Date: Fri Jan 9 11:13:39 2009 -0800
6g cleanup suggested by ken.
remove TPTR wrapper around TMAP, TCHAN, TSTRING.
R=ken
OCL=22406
CL=22409
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a91af04c06e306e87f9b8e2efda41a32ffd75476
元コミット内容
6g cleanup suggested by ken. remove TPTR wrapper around TMAP, TCHAN, TSTRING.
このコミットは、ken(おそらくKen Thompson)によって提案された6gコンパイラのクリーンアップであり、TMAP、TCHAN、TSTRINGといった型に対するTPTR(ポインタ型)ラッパーを削除することを目的としています。
変更の背景
Go言語の初期のコンパイラ(6gはx86-64アーキテクチャ向けのコンパイラ、gcは共通のフロントエンド部分)では、マップ、チャネル、文字列といった複合型が、内部的に常にポインタとして扱われていました。これは、これらの型がヒープ上に割り当てられ、そのポインタが変数として扱われるためです。しかし、コンパイラの内部処理において、これらの型が「ポインタへのポインタ」のように二重にラップされているかのような表現になっている箇所があり、コードの複雑性を増していました。
このコミットの背景には、コンパイラのコードベースを簡素化し、より直感的で一貫性のある型表現に統一するという目的があります。TMAP, TCHAN, TSTRINGはGo言語の組み込み型であり、その性質上、常に参照型として扱われます。そのため、コンパイラ内部でこれらを明示的にポインタ型としてラップするTPTRの概念は冗長であり、コードの可読性や保守性を低下させる要因となっていました。この変更は、これらの型を直接その種類として認識し、ポインタとしての性質は暗黙的に扱うことで、コンパイラのロジックをよりクリーンにすることを目指しています。
前提知識の解説
このコミットを理解するためには、Goコンパイラの初期の内部構造と型システムに関する基本的な知識が必要です。
- Goコンパイラ (
6g,gc):6g: Go言語の初期のコンパイラの一つで、主にx86-64アーキテクチャをターゲットとしていました。Goコンパイラは、フロントエンド(gc)とバックエンド(6g,8g,5gなど)に分かれていました。gc: Goコンパイラの共通フロントエンド部分で、ソースコードのパース、型チェック、AST(抽象構文木)の構築、最適化などを行います。
- Go言語の型システム:
map(TMAP): キーと値のペアを格納するハッシュテーブル。Goでは参照型であり、make関数で初期化されます。chan(TCHAN): ゴルーチン間の通信に使用されるチャネル。Goでは参照型であり、make関数で初期化されます。string(TSTRING): 不変のバイトシーケンス。Goでは値型のように振る舞いますが、内部的にはポインタと長さで構成されます。
- コンパイラ内部の型表現:
- Goコンパイラは、ソースコードの型を内部的な
Type構造体で表現します。このType構造体には、型の種類を示すetype(element type)フィールドが含まれます。 TPTR: コンパイラ内部でポインタ型を表すetypeの一つ。例えば、*intはTPTRのetypeを持ち、そのtypeフィールドがint型を指します。TMAP,TCHAN,TSTRING: これらもetypeとして定義されており、それぞれマップ、チャネル、文字列を表します。isptrto(Type *t, int et):tがetへのポインタ型であるかどうかをチェックするヘルパー関数。例えば、isptrto(someType, TSTRING)はsomeTypeが*string型であるかをチェックします。istype(Type *t, int et):tがet型そのものであるかをチェックする新しいヘルパー関数。ptrto(Type *t):t型へのポインタ型を生成する関数。
- Goコンパイラは、ソースコードの型を内部的な
このコミット以前は、map、chan、stringといった型が、コンパイラ内部でTPTR(ポインタ)としてラップされた形で扱われることがありました。例えば、map[int]stringという型は、コンパイラ内部では*map[int]stringのように表現され、さらにそのmap[int]string自体がTMAPというetypeを持つ、といった具合です。この二重のポインタ表現が、コードの混乱を招いていました。
技術的詳細
このコミットの主要な技術的変更は、TMAP、TCHAN、TSTRINGといった型が、コンパイラ内部で明示的なTPTRラッパーを介さずに直接扱われるように修正された点です。
具体的には、以下の変更が行われています。
-
ptrto関数の呼び出しの削除:src/cmd/gc/go.y(Go言語の文法定義ファイル) において、TMAP、TCHAN型の生成時にptrto($$)という呼び出しが削除されています。これは、これらの型が構文解析の段階で自動的にポインタとして扱われるのではなく、その型自体として認識されるようになったことを意味します。- 例:
$$ = typ(TMAP); $$->down = $3; $$->type = $5; $$ = ptrto($$);から$$ = typ(TMAP); $$->down = $3; $$->type = $5;へ変更。
-
isptrtoからistypeへの置き換え:src/cmd/6g/cgen.c、src/cmd/gc/const.c、src/cmd/gc/subr.c、src/cmd/gc/walk.cなど、多くのファイルでisptrto(t, TMAP)、isptrto(t, TCHAN)、isptrto(t, TSTRING)といったチェックが、istype(t, TMAP)、istype(t, TCHAN)、istype(t, TSTRING)に置き換えられています。- これは、以前は「
TMAPへのポインタ型であるか?」をチェックしていた箇所が、「TMAP型そのものであるか?」をチェックするように変更されたことを示します。これにより、コンパイラがこれらの型をより直接的に認識するようになります。
-
simtype配列の初期化:src/cmd/6g/align.cにおいて、simtype[TMAP] = tptr;、simtype[TCHAN] = tptr;、simtype[TSTRING] = tptr;という行が追加されています。simtype配列は、型の「単純化された」または「類似した」型をマッピングするために使用されます。この変更は、TMAP、TCHAN、TSTRINGが、アライメントやメモリレイアウトの観点からはポインタ型(tptr)と同様に扱われるべきであることをコンパイラに明示しています。これは、これらの型が内部的にポインタとして実装されているという事実を反映していますが、コード上では明示的なTPTRラッパーを必要としないようにするための調整です。
-
型チェックロジックの簡素化:
src/cmd/gc/dcl.cでは、TCHAN,TMAP,TSTRINGが「ポインタ形式でのみ存在できる」というエラーチェックが削除されています。これは、これらの型がもはや明示的なポインタ型として宣言される必要がなく、その型自体が参照型としての性質を持つようになったためです。src/cmd/gc/subr.cのalgtype関数やwhatis関数、Tpretty関数(型を文字列に変換する関数)などでも、TPTRを介したTMAP,TCHAN,TSTRINGの判別ロジックが簡素化され、直接t->etype == TMAPなどのチェックに置き換えられています。
これらの変更は、Goコンパイラの型システムにおけるTMAP、TCHAN、TSTRINGの表現をより自然で効率的なものに移行させるためのものです。これにより、コンパイラのコードベースがよりクリーンになり、将来的な機能追加や最適化が容易になります。
コアとなるコードの変更箇所
このコミットの核心を示す変更箇所は多岐にわたりますが、特に以下のファイルとコードスニペットが重要です。
-
src/cmd/gc/go.y(文法定義ファイル):TMAPやTCHANの型定義からptrto($$)の呼び出しが削除された箇所。--- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1031,7 +1031,6 @@ convtype: $$ = typ(TMAP); $$->down = $3; $$->type = $5; - $$ = ptrto($$); } | structtype @@ -1116,21 +1115,18 @@ Aothertype: $$ = typ(TCHAN); $$->type = $3; $$->chan = Crecv; - $$ = ptrto($$); } | LCHAN LCOMM Anon_chan_type { $$ = typ(TCHAN); $$->type = $3; $$->chan = Csend; - $$ = ptrto($$); } | LMAP '[' type ']' Atype { $$ = typ(TMAP); $$->down = $3; $$->type = $5; - $$ = ptrto($$); } | '*' Atype { -
src/cmd/6g/cgen.c(コード生成):isptrtoがistypeに置き換えられた箇所。--- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -218,7 +218,7 @@ cgen(Node *n, Node *res) break; case OLEN: - if(isptrto(nl->type, TSTRING)) { + if(istype(nl->type, TSTRING)) { regalloc(&n1, types[tptr], res); cgen(nl, &n1); @@ -237,7 +237,7 @@ cgen(Node *n, Node *res) regfree(&n1); break; } - if(isptrto(nl->type, TMAP)) { + if(istype(nl->type, TMAP)) { regalloc(&n1, types[tptr], res); cgen(nl, &n1); n1.op = OINDREG; -
src/cmd/6g/align.c(アライメント処理):simtype配列にTMAP,TCHAN,TSTRINGが追加された箇所。--- a/src/cmd/6g/align.c +++ b/src/cmd/6g/align.c @@ -219,6 +219,10 @@ belexinit(int lextype) Sym *s; Type *t; + simtype[TMAP] = tptr; + simtype[TCHAN] = tptr; + simtype[TSTRING] = tptr; + zprog.link = P; zprog.as = AGOK; zprog.from.type = D_NONE; -
src/cmd/gc/go.h(ヘッダーファイル): 新しいヘルパー関数istypeの宣言。--- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -626,6 +626,7 @@ void dump(char*, Node*); Type* aindex(Node*, Type*); int isnil(Node*); int isptrto(Type*, int); +int istype(Type*, int); int isptrsarray(Type*); int isptrdarray(Type*); int issarray(Type*);
コアとなるコードの解説
上記の変更箇所は、Goコンパイラの型システムにおけるTMAP、TCHAN、TSTRINGの扱いを根本的に変更しています。
-
src/cmd/gc/go.yの変更:- Go言語のソースコードがコンパイラによって解析される際、
mapやchanといったキーワードが検出されると、それに対応する内部型が構築されます。 - 以前は、これらの型が構築された直後に
ptrto($$)という関数が呼び出され、明示的にポインタ型としてラップされていました。これは、Goのマップやチャネルが常に参照型として機能するため、コンパイラ内部でもそのように表現する必要があったためです。 - このコミットでは、
ptrto($$)の呼び出しが削除されました。これは、コンパイラがこれらの型を「ポインタへのポインタ」としてではなく、「マップ型そのもの」や「チャネル型そのもの」として直接認識するようになったことを意味します。ポインタとしての性質は、これらの型が参照型であるというGo言語のセマンティクスによって暗黙的に保証されるようになりました。これにより、コンパイラの型構築ロジックが簡素化され、より直感的になりました。
- Go言語のソースコードがコンパイラによって解析される際、
-
src/cmd/6g/cgen.cの変更:cgen.cは、GoのAST(抽象構文木)を機械語に変換するコード生成のフェーズを担当します。OLEN(len関数)の処理において、以前はisptrto(nl->type, TSTRING)やisptrto(nl->type, TMAP)を使って、引数が文字列へのポインタ型やマップへのポインタ型であるかをチェックしていました。- この変更により、
istype(nl->type, TSTRING)やistype(nl->type, TMAP)に置き換えられました。これは、len関数の引数が「文字列型そのもの」や「マップ型そのもの」であるかを直接チェックするようになったことを意味します。コンパイラは、これらの型が内部的にポインタとして扱われることを知っているため、明示的なポインタチェックは不要になりました。これにより、コード生成ロジックがより直接的で、型のセマンティクスに忠実になりました。
-
src/cmd/6g/align.cの変更:align.cは、データのアライメントやメモリレイアウトに関する処理を担当します。simtype配列は、異なる型がメモリレイアウトの観点から「類似している」と見なされる場合に使用されます。例えば、int32とfloat32は異なる型ですが、メモリ上では同じサイズとアライメントを持つため、simtypeで関連付けられることがあります。simtype[TMAP] = tptr;などの追加は、TMAP、TCHAN、TSTRINGが、メモリレイアウトの観点からは汎用ポインタ型(tptr)と同様に扱われるべきであることをコンパイラに指示しています。これは、これらの型がヒープ上に割り当てられ、そのポインタがメモリ上で扱われるという事実を反映しています。この変更は、コンパイラのバックエンドがこれらの型を効率的に処理するための内部的な調整です。
-
src/cmd/gc/go.hの変更:istype関数の追加は、このコミット全体の変更をサポートするための新しいユーティリティ関数です。isptrtoが「ポインタへのポインタ」のような間接的なチェックを行うのに対し、istypeは「型そのもの」の直接的なチェックを可能にします。これにより、コンパイラのコードがより明確になり、意図が伝わりやすくなりました。
これらの変更は、Goコンパイラの内部的な型表現を簡素化し、map、chan、stringといった参照型をより自然な形で扱えるようにするための重要なステップでした。これにより、コンパイラのコードベースの保守性が向上し、将来的な言語機能の追加や最適化の基盤が強化されました。
関連リンク
- Go言語の初期のコンパイラに関する情報:
- Go Language Compilers (Go公式ドキュメント)
- A brief history of Go (Go公式ブログ)
参考にした情報源リンク
- 上記のGitHubコミットページ: https://github.com/golang/go/commit/a91af04c06e306e87f9b8e2efda41a32ffd75476
- Go言語の型システムに関する一般的な情報 (Go公式ドキュメントなど)
- Goコンパイラのソースコード (特に
src/cmd/gcとsrc/cmd/6gディレクトリ) - Go言語の初期の設計に関する議論やメーリングリストのアーカイブ (必要に応じて)