Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1560] ファイルの概要

このコミットは、Go言語の初期のコンパイラ(gc)におけるprint組み込み関数の挙動に関する修正です。具体的には、map型とchan型(チャネル型)の値をprint関数で出力する際に、それらをポインタとして扱うように変更し、sys.printpointer関数を呼び出すようにしています。これにより、これらの複合型がより適切に表現されるようになります。

コミット

print(map) and print(chan) as pointers.

R=ken
OCL=23520
CL=23520

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/3c5f3a864115a3d06d531adf71df02d208b7ab25

元コミット内容

commit 3c5f3a864115a3d06d531adf71df02d208b7ab25
Author: Russ Cox <rsc@golang.org>
Date:   Mon Jan 26 15:36:28 2009 -0800

    print(map) and print(chan) as pointers.
    
    R=ken
    OCL=23520
    CL=23520
---
 src/cmd/gc/sys.go      | 2 +--
 src/cmd/gc/sysimport.c | 2 +--
 src/cmd/gc/walk.c      | 6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/cmd/gc/sys.go b/src/cmd/gc/sys.go
index fc10f181a8..dbe446cb73 100644
--- a/src/cmd/gc/sys.go
+++ b/src/cmd/gc/sys.go
@@ -16,7 +16,7 @@ func	printbool(bool);
 func	printfloat(float64);
 func	printint(int64);
 func	printstring(string);
-func	printpointer(*any);
+func	printpointer(any);
 func	printinter(any);
 func	printarray(any);
 func	printnl();
diff --git a/src/cmd/gc/sysimport.c b/src/cmd/gc/sysimport.c
index bccc8f877f..08b9adfb7f 100644
--- a/src/cmd/gc/sysimport.c
+++ b/src/cmd/gc/sysimport.c
@@ -8,7 +8,7 @@ char *sysimport =
 	"func sys.printfloat (? float64)\\n"\n
 	"func sys.printint (? int64)\\n"\n
 	"func sys.printstring (? string)\\n"\n
-"func sys.printpointer (? *any)\\n"\n
+"func sys.printpointer (? any)\\n"\n
 	"func sys.printinter (? any)\\n"\n
 	"func sys.printarray (? any)\\n"\n
 	"func sys.printnl ()\\n"\n
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index e7a95d2699..48ab2a6c99 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1983,9 +1983,9 @@ loop:
 			argtype(on, l->type);		// any-1
 			break;
 		}
-		if(isptr[l->type->etype]) {
+		if(isptr[l->type->etype] || l->type->etype == TCHAN || l->type->etype == TMAP) {
 			on = syslook("printpointer", 1);
-			argtype(on, l->type->type);	// any-1
+			argtype(on, l->type);	// any-1
 			break;
 		}
 		if(isslice(l->type)) {
@@ -1993,7 +1993,7 @@ loop:
 			argtype(on, l->type);	// any-1
 			break;
 		}
-		badtype(n->op, l->type, T);\n
+		badtype(OPRINT, l->type, T);\n
 		l = listnext(&save);\n
 		goto loop;\n
 

変更の背景

Go言語の初期開発段階において、print組み込み関数はデバッグや簡単な出力のために広く利用されていました。しかし、map(マップ)やchan(チャネル)のような複合データ型をprint関数で出力する際に、その内部表現が適切に表示されないという問題がありました。

Go言語では、mapchanは参照型であり、その実体はヒープ上に確保され、変数はその実体へのポインタを保持します。したがって、これらの型をprintで出力する際には、そのポインタ値(メモリ上のアドレス)を表示することが、デバッグや内部状態の理解において有用であると考えられました。

このコミットは、mapchanprint関数に渡された際に、既存のポインタ型と同様にsys.printpointer関数を通じてそのアドレスを出力するように修正することで、この問題を解決しようとしたものです。これにより、printの出力がこれらの型の実際のメモリ表現をより正確に反映するようになります。

前提知識の解説

Go言語のprint組み込み関数

Go言語には、デバッグや簡単な出力のためにprintおよびprintlnという組み込み関数が存在します。これらはfmtパッケージのPrintfPrintlnとは異なり、より低レベルな出力メカニズムを提供します。特に、コンパイラ内部で型に応じた出力処理を呼び出すために使用されます。

Go言語のmap

mapはキーと値のペアを格納するハッシュテーブルの実装です。Go言語においてmapは参照型であり、make関数で初期化されたmap変数は、内部的にハッシュテーブルの実体へのポインタを保持します。map変数を別の変数に代入すると、ポインタがコピーされるため、両方の変数が同じ基盤となるハッシュテーブルを参照します。

Go言語のchan

chan(チャネル)は、Goルーチン間で値を送受信するための通信メカニズムです。mapと同様に、chanも参照型であり、make関数で初期化されたチャネル変数は、チャネルの実体へのポインタを保持します。チャネルを介した通信は、この実体を介して行われます。

ポインタ

ポインタは、メモリ上の特定のアドレスを指し示す変数です。Go言語では、C言語のようなポインタ演算は制限されていますが、変数のアドレスを取得したり、ポインタを介して値にアクセスしたりすることは可能です。参照型(map, chan, スライスなど)は、その実体へのポインタを内部的に保持しています。

Goコンパイラ(gc)の構造

このコミットが修正しているファイルは、Go言語の初期のコンパイラであるgc(Go Compiler)の一部です。gcは、Goのソースコードを機械語に変換する役割を担っています。

  • src/cmd/gc/sys.go: コンパイラ内部で利用される組み込み関数(printなど)の宣言が含まれています。これらはGo言語のソースコードからは直接呼び出されず、コンパイラが特殊な処理を行うために使用されます。
  • src/cmd/gc/sysimport.c: sys.goで宣言された組み込み関数のC言語での定義(またはそのインポート情報)が含まれています。これは、コンパイラがこれらの関数をどのように扱うかを定義する部分です。
  • src/cmd/gc/walk.c: コンパイラの「ウォーカー」フェーズを担当するファイルです。このフェーズでは、抽象構文木(AST)を走査し、型チェック、最適化、コード生成のための変換など、様々な処理を行います。print組み込み関数の呼び出しがどのように処理されるかを決定するロジックが含まれています。

技術的詳細

このコミットは、print組み込み関数がmap型とchan型を処理する方法を変更するために、Goコンパイラの3つのファイルに修正を加えています。

  1. src/cmd/gc/sys.goの変更: func printpointer(*any); から func printpointer(any); へと変更されています。 これは、sys.printpointer関数が、以前は任意のポインタ型(*any)を受け取るように宣言されていたのに対し、任意の型(any)を受け取るように変更されたことを意味します。これにより、printpointerはより汎用的な引数を受け入れられるようになり、mapchanのような参照型を直接渡せるようになります。

  2. src/cmd/gc/sysimport.cの変更: "func sys.printpointer (? *any)\\n" から "func sys.printpointer (? any)\\n" へと変更されています。 これは、sys.goでの変更に対応するもので、コンパイラが内部的にsys.printpointerのシグネチャを認識する方法を更新しています。これにより、コンパイラはprintpointerが任意の型を受け取ることを正しく理解し、型チェックやコード生成の際に整合性を保つことができます。

  3. src/cmd/gc/walk.cの変更: このファイルは、print組み込み関数の呼び出しがどのように処理されるかを決定するコンパイラのコア部分です。

    • if(isptr[l->type->etype]) { ... } の条件文が if(isptr[l->type->etype] || l->type->etype == TCHAN || l->type->etype == TMAP) { ... } に変更されました。 これは、print関数に渡された引数の型(l->type->etype)がポインタ型である場合に加えて、TCHAN(チャネル型)またはTMAP(マップ型)である場合にも、sys.printpointer関数を呼び出すように指示しています。
    • argtype(on, l->type->type); から argtype(on, l->type); へと変更されました。 これは、sys.printpointerに渡す引数の型を決定する部分です。以前は、ポインタの指す先の型(l->type->type)を渡していましたが、変更後は引数自体の型(l->type)を渡すようになります。これは、sys.printpointerのシグネチャがanyになったことと整合しています。mapchanはそれ自体が参照型であるため、その型情報をそのままprintpointerに渡すことで、内部でそのポインタ値を適切に処理できるようになります。
    • badtype(n->op, l->type, T); から badtype(OPRINT, l->type, T); へと変更されました。 これは、print関数に渡された型が不正である場合にエラーを報告する部分です。n->opは現在のノードの操作を表しますが、OPRINTと明示することで、print操作における型エラーであることをより明確にしています。

これらの変更により、print関数がmapchanを受け取った際に、それらをポインタとして扱い、sys.printpointerを通じてそのアドレスを出力する一貫した挙動が実現されます。

コアとなるコードの変更箇所

src/cmd/gc/sys.go

--- a/src/cmd/gc/sys.go
+++ b/src/cmd/gc/sys.go
@@ -16,7 +16,7 @@ func	printbool(bool);
 func	printfloat(float64);
 func	printint(int64);
 func	printstring(string);
-func	printpointer(*any);
+func	printpointer(any);
 func	printinter(any);
 func	printarray(any);
 func	printnl();

src/cmd/gc/sysimport.c

--- a/src/cmd/gc/sysimport.c
+++ b/src/cmd/gc/sysimport.c
@@ -8,7 +8,7 @@ char *sysimport =
 	"func sys.printfloat (? float64)\\n"\n
 	"func sys.printint (? int64)\\n"\n
 	"func sys.printstring (? string)\\n"\n
-"func sys.printpointer (? *any)\\n"\n
+"func sys.printpointer (? any)\\n"\n
 	"func sys.printinter (? any)\\n"\n
 	"func sys.printarray (? any)\\n"\n
 	"func sys.printnl ()\\n"\n

src/cmd/gc/walk.c

--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1983,9 +1983,9 @@ loop:
 			argtype(on, l->type);		// any-1
 			break;
 		}
-		if(isptr[l->type->etype]) {
+		if(isptr[l->type->etype] || l->type->etype == TCHAN || l->type->etype == TMAP) {
 			on = syslook("printpointer", 1);
-			argtype(on, l->type->type);	// any-1
+			argtype(on, l->type);	// any-1
 			break;
 		}
 		if(isslice(l->type)) {
@@ -1993,7 +1993,7 @@ loop:
 			argtype(on, l->type);	// any-1
 			break;
 		}
-		badtype(n->op, l->type, T);\n
+		badtype(OPRINT, l->type, T);\n
 		l = listnext(&save);\n
 		goto loop;\n
 

コアとなるコードの解説

src/cmd/gc/sys.go および src/cmd/gc/sysimport.c の変更

これらのファイルにおけるprintpointer関数のシグネチャの変更は、printpointerがより汎用的な引数を受け入れられるようにするためのものです。

  • *anyからanyへの変更は、printpointerが特定のポインタ型だけでなく、任意の型の値を直接受け取れるようになったことを示します。これは、mapchanが参照型であり、その実体へのポインタを内部的に持つため、それらの型自体をprintpointerに渡すことで、内部でポインタ値として処理できるようにするためです。

src/cmd/gc/walk.c の変更

このファイルは、print組み込み関数のセマンティクスを定義する上で最も重要な変更を含んでいます。

  • if(isptr[l->type->etype] || l->type->etype == TCHAN || l->type->etype == TMAP): この条件文は、print関数に渡された引数lの型が、既存のポインタ型(isptr[l->type->etype])であるか、新たにTCHAN(チャネル型)またはTMAP(マップ型)である場合に真となります。これにより、mapchanもポインタと同様の出力パスを通るようになります。

  • argtype(on, l->type);: この行は、sys.printpointer関数を呼び出す際に、引数としてlの型情報全体(l->type)を渡すように変更されています。以前はl->type->type(ポインタの指す先の型)を渡していましたが、printpointeranyを受け取るようになったため、mapchanのような参照型をそのまま渡すことで、その内部のポインタ値をprintpointerが適切に解釈できるようになります。

  • badtype(OPRINT, l->type, T);: この変更は、print関数に不正な型の引数が渡された場合に発生するエラーメッセージをより具体的にするためのものです。n->opは一般的な操作を表すのに対し、OPRINTprint操作に特化した定数であり、エラーの発生源を明確にします。

これらの変更の組み合わせにより、Goコンパイラはprint(map)print(chan)が呼び出された際に、これらの型の内部的なポインタ値を抽出し、sys.printpointerを通じて出力するようになります。これにより、デバッグ時にこれらの複合型のメモリ上の位置を把握できるようになり、開発者にとってより有用な情報が提供されることになります。

関連リンク

  • Go言語のprint組み込み関数に関する議論やドキュメント(当時のものを見つけるのは困難ですが、Goの歴史的な文脈で探す必要があります)
  • Go言語のmap型に関する公式ドキュメント
  • Go言語のchan型に関する公式ドキュメント

参考にした情報源リンク

  • Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
  • Go言語の初期のコミット履歴
  • Go言語のmapchanの内部実装に関する一般的な知識
  • Go言語のコンパイラ(gc)の構造に関する一般的な知識I have extracted the commit information and outlined the plan. Now I will perform a web search to gather more context for the "変更の背景" and "前提知識の解説" sections.

My search query will be: "Go language print map chan pointers early compiler" or similar to find historical context.

After the web search, I will compile all the information into the requested Markdown format.

print(default_api.google_web_search(query="Go language print map chan pointers early compiler"))