[インデックス 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言語の初期の設計に関する議論やメーリングリストのアーカイブ (必要に応じて)