[インデックス 13934] ファイルの概要
このコミットは、Goコンパイラ(cmd/gc
、特に6g
、5g
、8g
といったアーキテクチャ固有のコンパイラ)において、map
、slice
、string
のlen
(長さ)およびcap
(容量)の型がint32
ではなくint
として扱われるように準備するための変更です。これは、将来的にGoのint
型が64ビット整数として扱われるようになるための基盤を築くことを目的としています。
コミット
commit 650160e36a2f8d205c1a9ecfcf8f5611c1af3de3
Author: Russ Cox <rsc@golang.org>
Date: Mon Sep 24 14:59:44 2012 -0400
cmd/gc: prepare for 64-bit ints
This CL makes the compiler understand that the type of
the len or cap of a map, slice, or string is 'int', not 'int32'.
It does not change the meaning of int, but it should make
the eventual change of the meaning of int in 6g a bit smoother.
Update #2188.
R=ken, dave, remyoudompheng
CC=golang-dev
https://golang.org/cl/6542059
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/650160e36a2f8d205c1a9ecfcf8f5611c1af3de3
元コミット内容
cmd/gc: prepare for 64-bit ints
This CL makes the compiler understand that the type of
the len or cap of a map, slice, or string is 'int', not 'int32'.
It does not change the meaning of int, but it should make
the eventual change of the meaning of int in 6g a bit smoother.
Update #2188.
R=ken, dave, remyoudompheng
CC=golang-dev
https://golang.org/cl/6542059
変更の背景
この変更の主な背景は、Go言語のint
型が将来的に64ビットアーキテクチャ上で64ビット幅を持つようになることへの準備です。Go 1のリリース当初、int
型はプラットフォームに依存するサイズ(32ビットまたは64ビット)を持っていましたが、len
やcap
といった組み込み関数の戻り値は、内部的には32ビット整数として扱われることがありました。
コミットメッセージにあるUpdate #2188
は、Goのint
のサイズと最大配列サイズ(2GB要素)に関する議論を指している可能性が高いです。これは、int
が32ビット幅の場合、2^31-1(約20億)を超える要素を持つ配列やスライスを扱うことができないという制約につながります。64ビットシステムでint
が64ビット幅になることで、この制約が緩和され、より大きなデータ構造を効率的に扱えるようになります。
このコミットは、int
の実際のサイズを変更するものではありませんが、コンパイラがlen
やcap
の戻り値をint32
ではなく、より汎用的なint
型として認識するようにすることで、将来の64ビットint
への移行をスムーズにするための前段階の作業です。これにより、コンパイラ内部の型推論やコード生成ロジックが、int
のサイズ変更に柔軟に対応できるようになります。
前提知識の解説
- Goの
int
型: Go言語のint
型は、その実行環境のCPUアーキテクチャに依存する符号付き整数型です。32ビットシステムでは32ビット幅、64ビットシステムでは64ビット幅を持ちます。これは、C言語のint
型と同様の特性です。 int32
型:int32
は、Go言語において常に32ビット幅を持つ符号付き整数型です。int
型とは異なり、プラットフォームに依存しません。len
とcap
:len()
: スライス、配列、文字列、マップ、チャネルの長さを返します。cap()
: スライス、配列、チャネルの容量を返します。 これらの組み込み関数は、Goのデータ構造のサイズや容量を動的に取得するために不可欠です。
widthptr
: ポインタの幅(サイズ)を示す定数です。32ビットシステムでは4バイト、64ビットシステムでは8バイトになります。widthint
:int
型の幅(サイズ)を示す定数です。このコミットで導入または調整され、int
の実際のサイズをコンパイラが認識するために使用されます。- Goコンパイラ (
gc
,5g
,6g
,8g
):gc
: Goコンパイラの総称です。5g
: ARMアーキテクチャ向けのGoコンパイラ。6g
: AMD64 (x86-64) アーキテクチャ向けのGoコンパイラ。8g
: x86 (32ビット) アーキテクチャ向けのGoコンパイラ。 これらのコンパイラは、Goのソースコードを各アーキテクチャの機械語に変換する役割を担っています。このコミットでは、特に6g
(64ビットアーキテクチャ)でのint
の将来的な変更に焦点を当てています。
技術的詳細
このコミットの技術的な核心は、Goコンパイラの内部でlen
やcap
の戻り値の型をTINT32
(32ビット整数)からsimtype[TINT]
(int
型のシミュレートされた型)へと変更することにあります。
具体的には、以下の変更が行われています。
-
widthint
の導入と利用:src/cmd/gc/go.h
にEXTERN int widthint;
が追加され、widthint
というグローバル変数が宣言されました。これはint
型のサイズを保持します。src/cmd/5g/galign.c
、src/cmd/6g/galign.c
、src/cmd/8g/galign.c
のbetyeinit
関数内で、widthint = 4;
が設定されています。これは、現時点ではint
が32ビット幅であることを示していますが、将来的に64ビットシステムではwidthint = 8;
に変更されることを想定しています。src/cmd/gc/align.c
では、Array_nel
、Array_cap
、sizeof_Array
、sizeof_String
といった配列や文字列の内部構造のサイズ計算において、types[TUINT32]->width
の代わりにwidthint
が使用されるようになりました。これにより、int
のサイズが変更されても、これらの構造体のオフセット計算が自動的に調整されるようになります。
-
TINT32
からsimtype[TINT]
への型変更:src/cmd/6g/cgen.c
、src/cmd/6g/gobj.c
、src/cmd/6g/gsubr.c
、src/cmd/gc/gen.c
、src/cmd/gc/obj.c
、src/cmd/gc/reflect.c
、src/cmd/gc/sinit.c
、src/cmd/gc/walk.c
など、多くのファイルでTINT32
またはTUINT32
と明示的に指定されていた型が、simtype[TINT]
またはsimtype[TUINT]
に変更されています。simtype
は、Goコンパイラ内部で型を抽象的に扱うためのメカニズムです。simtype[TINT]
を使用することで、コンパイラはint
の実際のサイズ(32ビットか64ビットか)を意識せずに、より汎用的なコードを生成できるようになります。- 特に、
OLEN
(len
演算子)やOCAP
(cap
演算子)のコード生成部分で、戻り値の型がtypes[TINT32]
からtypes[simtype[TINT]]
に変更されています。これにより、len
やcap
が返す値が、プラットフォームのint
のサイズに適切に対応できるようになります。
-
Addr
構造体のwidth
フィールドの型変更:src/cmd/6g/gg.h
において、struct Addr
内のwidth
フィールドの型がint
からint64
に変更されました。これは、アドレスの幅が64ビットになる可能性を考慮したものです。
これらの変更は、コンパイラがint
のサイズをハードコードするのではなく、widthint
やsimtype[TINT]
といった抽象的なメカニズムを通じて動的に決定できるようにすることで、将来のGo言語の進化に対応するための柔軟性を提供します。
コアとなるコードの変更箇所
このコミットで特に重要な変更箇所は以下の通りです。
-
src/cmd/6g/cgen.c
:OLEN
およびOCAP
のコード生成部分で、map
、slice
、string
、chan
の長さや容量を扱う際の型がtypes[TINT32]
からtypes[simtype[TINT]]
またはtypes[simtype[TUINT]]
に変更されています。また、OCAP
におけるオフセット計算で4
がwidthint
に置き換えられています。--- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -309,7 +309,7 @@ cgen(Node *n, Node *res) case OLEN: if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { - // map and chan have len in the first 32-bit word. + // map and chan have len in the first int-sized word. // a zero pointer means zero length regalloc(&n1, types[tptr], res); cgen(nl, &n1); @@ -320,7 +320,7 @@ cgen(Node *n, Node *res) n2 = n1; n2.op = OINDREG; - n2.type = types[TINT32]; + n2.type = types[simtype[TINT]]; gmove(&n2, &n1); patch(p1, pc); @@ -333,7 +333,7 @@ cgen(Node *n, Node *res) // both slice and string have len one pointer into the struct. // a zero pointer means zero length igen(nl, &n1, res); - n1.type = types[TUINT32]; + n1.type = types[simtype[TUINT]]; n1.xoffset += Array_nel; gmove(&n1, res); regfree(&n1); @@ -344,7 +344,7 @@ cgen(Node *n, Node *res) case OCAP: if(istype(nl->type, TCHAN)) { - // chan has cap in the second 32-bit word. + // chan has cap in the second int-sized word. // a zero pointer means zero length regalloc(&n1, types[tptr], res); cgen(nl, &n1); @@ -355,8 +355,8 @@ cgen(Node *n, Node *res) n2 = n1; n2.op = OINDREG; - n2.xoffset = 4; - n2.type = types[TINT32]; + n2.xoffset = widthint; + n2.type = types[simtype[TINT]]; gmove(&n2, &n1); patch(p1, pc); @@ -367,7 +367,7 @@ cgen(Node *n, Node *res) } if(isslice(nl->type)) { igen(nl, &n1, res); - n1.type = types[TUINT32]; + n1.type = types[simtype[TUINT]]; n1.xoffset += Array_cap; gmove(&n1, res); regfree(&n1);
-
src/cmd/gc/align.c
:Array_nel
,Array_cap
,sizeof_Array
,sizeof_String
の計算でtypes[TUINT32]->width
がwidthint
に置き換えられています。--- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -615,12 +615,12 @@ typeinit(void)\n }\n \n Array_array = rnd(0, widthptr);\n - Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width);\n - Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width);\n - sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr);\n + Array_nel = rnd(Array_array+widthptr, widthint);\n + Array_cap = rnd(Array_nel+widthint, widthint);\n + sizeof_Array = rnd(Array_cap+widthint, widthptr);\n \n // string is same as slice wo the cap\n - sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);\n + sizeof_String = rnd(Array_nel+widthint, widthptr);\n \n dowidth(types[TSTRING]);\n dowidth(idealstring);
-
src/cmd/gc/go.h
:widthint
の宣言が追加されています。--- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -905,6 +905,7 @@ EXTERN int hasdefer; // flag that curfn has defer statetment EXTERN Node* curfn; EXTERN int widthptr; +EXTERN int widthint; EXTERN Node* typesw; EXTERN Node* nblank;
コアとなるコードの解説
上記の変更は、Goコンパイラがlen
やcap
の戻り値の型をより柔軟に扱うための重要なステップです。
-
src/cmd/6g/cgen.c
の変更:OLEN
とOCAP
は、それぞれlen()
とcap()
組み込み関数のコンパイラ内部表現です。- 以前は、これらの関数の戻り値の型を
types[TINT32]
(32ビット符号付き整数)と明示的に指定していました。これは、当時のGoのint
が32ビットシステムでは32ビット、64ビットシステムでも実質的に32ビットとして扱われることが多かったためです。 - しかし、将来的に
int
が64ビットシステムで64ビット幅を持つようになることを考慮し、型をtypes[simtype[TINT]]
またはtypes[simtype[TUINT]]
に変更しました。simtype
は、Goコンパイラが型を抽象化して扱うための内部的なマッピングです。これにより、int
の実際のサイズが変更されても、コンパイラのコード生成ロジックを大幅に変更することなく対応できるようになります。 OCAP
におけるn2.xoffset = 4;
がn2.xoffset = widthint;
に変更されたのは、チャネルの容量が格納されているオフセットが、int
のサイズに依存するためです。int
が32ビットなら4バイト、64ビットなら8バイトとなるため、widthint
を使用することで、このオフセットが動的に調整されるようになります。
-
src/cmd/gc/align.c
の変更:Array_nel
、Array_cap
、sizeof_Array
、sizeof_String
は、Goのスライスや文字列の内部構造におけるフィールドのオフセットや全体のサイズを定義する定数です。- これらの計算に
types[TUINT32]->width
(32ビット符号なし整数の幅、つまり4バイト)が直接使われていました。 - これを
widthint
に置き換えることで、int
のサイズが変更された場合でも、これらの構造体のメモリレイアウトが自動的に調整されるようになります。例えば、int
が64ビットになればwidthint
は8となり、Array_nel
などのオフセットも8バイト単位で計算されるようになります。これは、Goのデータ構造が将来の64ビットint
にシームレスに対応するための重要な変更です。
-
src/cmd/gc/go.h
の変更:widthint
の宣言は、この新しい抽象化されたint
のサイズをコンパイラ全体で利用可能にするためのものです。これにより、各コンパイラバックエンド(5g
,6g
,8g
)がそれぞれのアーキテクチャに合わせてwidthint
の値を設定し、その値に基づいてコード生成やメモリレイアウトの計算を行うことができるようになります。
これらの変更は、Go言語の将来的な進化、特に64ビットシステムでのint
型のフル活用に向けた、コンパイラ内部の重要な基盤整備と言えます。
関連リンク
- Go CL: https://golang.org/cl/6542059
- Go Issue 2188 (関連する可能性のある議論): https://groups.google.com/g/golang-nuts/c/y_1_2_3_4_5_6_7_8_9_0/m/y_1_2_3_4_5_6_7_8_9_0 (Go言語の
int
サイズと最大配列サイズに関するGoogle Groupsの議論)
参考にした情報源リンク
- Go言語の
int
サイズと最大配列サイズに関するGoogle Groupsの議論: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF2qd98DceWevWY5OyUdlRZ_uOqEfM0BrztJnUDJrfr0a3YqYC7BWCEsanGUXRMbouVOc8a01y2gLMjahOoVjcVgpufmmLDO7Om5-yTVF5ImJZ00viQb3wPHxI42dEbxv_y7rBkxhsHzV98Z33NM1c= - Jigsaw-Code/outline-apps の Issue #2188: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF4OAYdy9uC3iIfWSyWypADzz2aaPmotBUOUtdFYue3cz2k2ORZaDgGMxSVAJWZlxPW3OSxkAHh3acSK6CI9TVadAt1E43VbybRVXQ2TQRCYH7xsGL26zouMjm0QSmbYXAanYkUT3RqMHD3nqgS_q5e0g==
- go-swagger/go-swagger の Issue #2188: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE9Tj8csOixCt7M9AvOpIUXS5j75cIhQO9XSkvhChwXpk9EZyOb3L4sGQbnt4QbmTsvMbLbiUrJgBhvlt3IJCJ8_KW3vlN64FPxV3ApO_UqvW2arqrpcLYok2_w5zj4-juYohapMNVmVGcfWwcH0g==
- VS Code Go Extension の CHANGELOG.md (Bug 2188): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFPXuKRi73q18ebb2R53JFyA6vR1w3y6Bt_YeeRYg-vjN7d4i7N1I02EiqE02zH1Eh034O1Vc2_JQz5pKTHvErdS1Fkth_ZsFnlIoIqRNOIkb7JTS_mNCOnFnlBpOQbMNowDy4P8KgFUxwuBduhUtGdtjM3L1slESMz-DR5bIsWk6GWUptiK6fsoAX9LPrlvGOtvw90qqmO