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

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

このコミットは、Goコンパイラの6g(amd64アーキテクチャ向け)のコード生成部分であるsrc/cmd/6g/cgen.cにおけるバグ修正です。具体的には、定数インデックスを持つ配列の処理において、誤った型チェック関数isptrdarrayが使用されていた箇所を、より汎用的なisdarrayに修正することで、コンパイラの正確性を向上させています。

コミット

  • コミットハッシュ: c9954c63a8f4f19be93dfaaaff8ca5afa65f25b5
  • Author: Ken Thompson ken@golang.org
  • Date: Thu Dec 18 22:01:46 2008 -0800

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

https://github.com/golang/go/commit/c9954c63a8f4f19be93dfaaaff8ca5afa65f25b5

元コミット内容

    bug in [const]
    
    R=r
    OCL=21569
    CL=21569

変更の背景

このコミットは、Goコンパイラの初期バージョンにおける配列の定数インデックス処理に関するバグを修正するために行われました。元のコードでは、配列の型をチェックする際にisptrdarrayという関数が使用されていましたが、これは「ポインタの配列」であるかどうかを判定するものでした。しかし、定数インデックスを持つ配列の処理においては、ポインタの配列に限定せず、より一般的な「データ配列」であるかどうかを判定する必要がありました。この誤った型チェックが、特定の条件下でコンパイラの誤動作や不正なコード生成を引き起こす可能性があったため、より適切なisdarray関数への変更が必要とされました。

前提知識の解説

Goコンパイラ 6g

6gは、Go言語の初期バージョン(Go 1.5以前)において、amd64アーキテクチャ(64ビットIntel/AMDプロセッサ)向けのコンパイラの名称でした。当時のGoコンパイラは、ターゲットアーキテクチャごとに6g(amd64)、8g(386)、5g(arm)といった異なる名前を持っていました。Go 1.5以降は、これらのコンパイラはgo tool compileコマンドに統合され、環境変数($GOARCHなど)に基づいて適切なアーキテクチャのコードを生成するようになりました。このコミットは、Go言語がまだ初期開発段階にあった頃の、C言語で書かれたコンパイラの一部に対する修正です。

cgen.c

cgen.cは、Goコンパイラのソースコードの一部であり、その名前が示す通り「コード生成(Code Generation)」を担当するC言語のファイルです。Goコンパイラの初期バージョンはC言語で実装されており、このファイルはGoのソースコードを機械語に変換する過程で、具体的な命令列を生成する役割を担っていました。Go 1.5以降、コンパイラ自体はGo言語で書き直されましたが、cgo(GoとCの相互運用)や一部のランタイムコンポーネントにはC言語のコードが残っています。

isptrdarrayisdarray

これらは、コンパイラの内部で使用される型チェック関数(またはマクロ)であると推測されます。

  • isptrdarray: "is pointer array"(ポインタの配列であるか)の略である可能性が高いです。これは、データ構造がポインタの配列であるかどうかを判定するために使用される関数と考えられます。
  • isdarray: "is data array"(データ配列であるか)または "is dynamic array"(動的配列であるか)の略である可能性があります。文脈から判断すると、より一般的な「データ配列」を指す可能性が高いです。Go言語における配列は固定長の値型であり、スライスが動的な配列のような振る舞いをしますが、コンパイラの内部処理では、これらの異なる配列の特性を区別し、適切に処理するための型チェックが必要となります。

このコミットでは、isptrdarrayからisdarrayへの変更が行われていることから、特定のコンテキストにおいて、ポインタの配列に限定したチェックではなく、より広範なデータ配列に対するチェックが必要であったことが示唆されます。これは、コンパイラが配列の要素へのアクセス(特に定数インデックスによるアクセス)を正しく処理するために、配列の基本的な性質(ポインタの配列か、それとも一般的なデータ配列か)を正確に識別する必要があったためと考えられます。

技術的詳細

このコミットの技術的詳細なポイントは、コンパイラのコード生成フェーズにおける配列の型チェックの正確性です。

src/cmd/6g/cgen.c内のagen関数は、おそらく「アドレス生成(address generation)」を担当する部分であり、変数や配列の要素のアドレスを計算する役割を担っています。配列の要素にアクセスする際、特に定数インデックス(例: arr[0], arr[5])を使用する場合、コンパイラはその配列がどのような種類であるかを正確に把握する必要があります。

元のコードでは、定数インデックスを持つ配列の処理において、isptrdarray(nl->type)という条件分岐が複数箇所で使用されていました。nl->typeは、おそらく配列の型情報を表すオブジェクトです。isptrdarrayが「ポインタの配列」を意味すると仮定すると、このチェックは、配列がポインタの配列である場合にのみ特定の処理を行うことを意図していたと考えられます。

しかし、定数インデックスによるアクセスは、ポインタの配列に限らず、あらゆる種類の配列(整数、文字列、構造体などの配列)に対して行われる可能性があります。もしisptrdarrayが厳密にポインタの配列のみを識別し、他の種類の配列を誤って除外していた場合、コンパイラは非ポインタの配列に対する定数インデックスアクセスを正しく処理できず、バグ(例: 誤ったアドレス計算、境界チェックの失敗、最適化の誤り)を引き起こす可能性がありました。

isdarrayへの変更は、この問題を解決します。isdarrayが「データ配列」全般を識別する関数であるならば、この変更によって、コンパイラはポインタの配列だけでなく、他のすべての種類の配列に対しても、定数インデックスアクセス時の適切なコード生成ロジックを適用できるようになります。これにより、コンパイラの堅牢性と正確性が向上し、より広範なGoプログラムを正しくコンパイルできるようになります。

具体的には、agen関数内の以下の3箇所でisptrdarrayisdarrayに置き換えられています。

  1. 定数インデックスの処理ブロック内。
  2. 境界チェックの処理ブロック内。
  3. アドレス生成の最終段階。

これらの変更は、配列の型に関わらず、定数インデックスアクセス時のアドレス計算、境界チェック、および最終的なコード生成ロジックが正しく適用されるようにするためのものです。

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

--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -485,7 +485,7 @@ agen(Node *n, Node *res)\n 		// constant index\n 		if(whatis(nr) == Wlitint) {\n 			v = mpgetfix(nr->val.u.xval);\n-			if(isptrdarray(nl->type)) {\n+			if(isdarray(nl->type)) {\n 
 				if(!debug['B']) {\n 					n1 = n3;\n @@ -536,7 +536,7 @@ agen(Node *n, Node *res)\n 
 		if(!debug['B']) {\n 			// check bounds\n-			if(isptrdarray(nl->type)) {\n+			if(isdarray(nl->type)) {\n 				n1 = n3;\n 				n1.op = OINDREG;\n 				n1.type = types[tptr];\n @@ -552,7 +552,7 @@ agen(Node *n, Node *res)\n 			patch(p1, pc);\n 		}\n 
-		if(isptrdarray(nl->type)) {\n+		if(isdarray(nl->type)) {\n 			n1 = n3;\n 			n1.op = OINDREG;\n 			n1.type = types[tptr];\n```

## コアとなるコードの解説

変更は`src/cmd/6g/cgen.c`ファイルの`agen`関数内で行われています。`agen`関数は、Goコンパイラがコードを生成する際に、メモリ上のアドレスを計算するための重要な関数です。

この関数内で、配列の要素にアクセスする際のインデックスが定数である場合(`if(whatis(nr) == Wlitint)`)、コンパイラは特定の最適化やチェックを行う必要があります。

変更された3つの`if`文は、それぞれ異なるコンテキストで配列の型をチェックしています。

1.  **最初の変更箇所 (`@@ -485,7 +485,7 @@`)**:
    これは、定数インデックスを持つ配列の処理の初期段階で行われる型チェックです。`isptrdarray(nl->type)`が`isdarray(nl->type)`に変更されたことで、ポインタの配列に限定せず、あらゆる種類のデータ配列に対して、この後のコード生成ロジックが適用されるようになりました。これにより、定数インデックスアクセス時のアドレス計算がより汎用的に、かつ正確に行われるようになります。

2.  **二番目の変更箇所 (`@@ -536,7 +536,7 @@`)**:
    この部分は、配列の境界チェック(bounds check)に関連しています。`if(!debug['B'])`という条件から、デバッグモードでない場合に境界チェックを行うことがわかります。ここでも`isptrdarray`が`isdarray`に置き換えられたことで、ポインタの配列だけでなく、すべてのデータ配列に対して適切な境界チェックが適用されるようになります。これにより、実行時エラー(パニック)の検出がより正確になります。

3.  **三番目の変更箇所 (`@@ -552,7 +552,7 @@`)**:
    これは、アドレス生成の最終段階、または特定の最適化パスに関連する部分である可能性があります。ここでも同様に`isptrdarray`が`isdarray`に置き換えられたことで、配列の型に関わらず、最終的なアドレス計算やレジスタ割り当てなどのコード生成が正しく行われるようになります。

これらの変更は、Goコンパイラが配列の定数インデックスアクセスを処理する際の内部ロジックを改善し、より堅牢で正確なコードを生成するための重要な修正です。

## 関連リンク

-   GitHub上のコミットページ: [https://github.com/golang/go/commit/c9954c63a8f4f19be93dfaaaff8ca5afa65f25b5](https://github.com/golang/go/commit/c9954c63a8f4f19be93dfaaaff8ca5afa65f25b5)

## 参考にした情報源リンク

-   Go compiler 6g: [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGPdAcg-FrK0ahIeYgXyoRcTmzYmag0LNBtkrmFbkExviWaHPQhcI3hOrdiZ6PIa8-RkNNas7egQ2R71C8-oGz1oUQLmGMeO4gIuF2INQFBEZNaIQ==](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGPdAcg-FrK0ahIeYgXyoRcTmzYmag0LNBtkrmFbkExviWaHPQhcI3hOrdiZ6PIa8-RkNNas7egQ2R71C8-oGz1oUQLmGMeO4gIuF2INQFBEZNaIQ==)
-   Go compiler 6g (Stack Overflow): [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGGzho4E2c5YmH_Hhp_eopnCDlZZjhw9ofCZrstL9_U8iWsdKvVTrgzRRvOPrfE_yFKmHBQqcFs1zMezCq6O71X6xXn9VcqTmBG95VZ22iuJmlM-tHLWTuGrrhFZZdsei6vQN0K1rrv4mv870LqOhrmFGKBeoia1ZBrgKvbiAw5pccb3KkURY4S-kcjmKdBqw==](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGGzho4E2c5YmH_Hhp_eopnCDlZZjhw9ofCZrstL9_U8iWsdKvVTrgzRRvOPrfE_yFKmHBQqcFs1zMezCq6O71X6xXn9VcqTmBG95VZ22iuJmlM-tHLWTuGrrhFZZdsei6vQN0K1rrv4mv870LqOhrmFGKBeoia1ZBrgKvbiAw5pccb3KkURY4S-kcjmKdBqw==)
-   Go compiler written in C (googlesource.com): [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH5cIe7zTtGNbEK-a1hFB_uy7mOHazjfeE0yQ5JspMfyqgpbvsCdriJEGIMi_Pu9d1J8cKOie5BvxKGALtMFVxBazFWr-jLoPg-SpwxEAUQYwz6xGipbSP_zxssa9jqcUlQtW0DiQ6ytHPxSui6g5qxyrSH9hvW5mytNBRmCd8S](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH5cIe7zTtGNbEK-a1hFB_uy7mOHazjfeE0yQ5JspMfyqgpbvsCdriJEGIMi_Pu9d1J8cKOie5BvxKGALtMFVxBazFWr-jLoPg-SpwxEAUQYwz6xGipbSP_zxssa9jqcUlQtW0DiQ6ytHPxSui6g5qxyrSH9hvW5mytNBRmCd8S)
-   Go arrays vs slices (Stack Overflow): [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFPx_U6Ps7JtL6sIxYsXA7oV6dm3I8voJ9HfVYHNNsBA2Cunj5U-O1ASC0_-7U5oCzKylz1-iI3hF2h03EPq4vCbVJwLLLk_GUhvzCxPSsotmzccXPuoUU49THTpJ1nueHxIuIt2NZa3717QVYVUJg1MCYWmJ0SUFLjv91QJaeQat1JnIaPX3c3m__bqdjn3Hv8MnQD5g6ZJZs=](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFPx_U6Ps7JtL6sIxYsXA7oV6dm3I8voJ9HfVYHNNsBA2Cunj5U-O1ASC0_-7U5oCzKylz1-iI3hF2h03EPq4vCbVJwLLLk_GUhvzCxPSsotmzccXPuoUU49THTpJ1nueHxIuIt2NZa3717QVYVUJg1MCYWmJ0SUFLjv91QJaeQat1JnIaPX3c3m__bqdjn3Hv8MnQD5g6ZJZs=)