[インデックス 13251] ファイルの概要
このコミットは、Go言語のランタイムにおける型情報構造体 commonType
に、ガベージコレクション(GC)関連の新しいフィールド gc
を追加するものです。このフィールドはコミット時点では未使用とされていますが、将来的なGCの機能拡張や最適化のために予約された領域と考えられます。Goの型システムとランタイム、そしてコンパイラとリンカにまたがる低レベルな変更を含んでいます。
コミット
commit 65e61d5770c7cbabe86e8159eb922e207942dde0
Author: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
Date: Sat Jun 2 14:02:44 2012 -0400
runtime: add (unused for now) gc field to type information
R=rsc
CC=golang-dev
https://golang.org/cl/6255074
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/65e61d5770c7cbabe86e8159eb922e207942dde0
元コミット内容
runtime: add (unused for now) gc field to type information
R=rsc
CC=golang-dev
https://golang.org/cl/6255074
変更の背景
Go言語のランタイムは、ガベージコレクション(GC)を効率的に実行するために、メモリ上の各オブジェクトがどのような型を持ち、その中にポインタがどこに存在するかという情報を必要とします。この情報は「型情報」としてランタイムに組み込まれています。
このコミットが行われた2012年6月は、Go 1.0がリリースされて間もない時期であり、GoのランタイムとGCは活発に開発・改善が進められていました。commonType
は、Goのすべての型が持つ共通のメタデータ構造であり、その定義を変更することは、Goの型システムとGCの根幹に関わる重要な変更です。
gc
フィールドの追加は、「現時点では未使用」と明記されていることから、将来的に導入されるであろう新しいGCアルゴリズムや最適化のために、型情報構造体にあらかじめGC関連のメタデータを格納する場所を確保しておくという、先見的な設計変更であると推測されます。これにより、将来のGC改善時に、型情報構造体のレイアウトを再度変更する必要がなくなるというメリットがあります。例えば、特定の型に特化したGCヒントや、GCがオブジェクトをスキャンする際の追加情報などを格納するために使用される可能性があります。
前提知識の解説
このコミットを理解するためには、以下のGo言語の内部構造に関する知識が必要です。
- Goランタイム (Go Runtime): Goプログラムは、OSの機能に直接依存するのではなく、Goランタイムと呼ばれる独自の実行環境上で動作します。ランタイムは、ゴルーチンのスケジューリング、メモリ管理(ガベージコレクションを含む)、チャネル通信など、Go言語の並行処理とメモリ安全性を実現するための低レベルな機能を提供します。
- ガベージコレクション (Garbage Collection, GC): Goは自動メモリ管理を採用しており、開発者が手動でメモリを解放する必要がありません。GCは、プログラムがもはや到達できない(参照されていない)メモリ領域を自動的に識別し、解放するプロセスです。GoのGCは、ヒープ上のオブジェクトをスキャンし、ポインタをたどって「生きている」オブジェクトを特定します。このスキャンには、各オブジェクトの型情報が不可欠です。
- 型情報 (Type Information): Goのランタイムは、プログラム内のすべての型に関するメタデータを持っています。このメタデータには、型のサイズ、アライメント、ハッシュ値、そして最も重要なこととして、その型がポインタを含むかどうか、またポインタがどこにあるかという情報が含まれます。この情報は、リフレクション(
reflect
パッケージ)やGCによって利用されます。 reflect
パッケージ: Goの標準ライブラリであるreflect
パッケージは、実行時に型情報を検査・操作するための機能を提供します。このパッケージが扱う型情報は、ランタイム内部の型情報構造体(commonType
など)に基づいています。commonType
構造体: Goのランタイムとreflect
パッケージで使用される、すべてのGoの型が共通して持つ基本情報(サイズ、ハッシュ、種類など)を定義する内部構造体です。この構造体は、Goのソースコード(src/pkg/reflect/type.go
,src/pkg/runtime/type.go
)と、C言語で書かれたランタイム部分(src/pkg/runtime/type.h
)の両方で定義され、コンパイラによって生成される型情報に影響を与えます。unsafe.Pointer
とuintptr
:unsafe.Pointer
: 任意の型のポインタを保持できる特殊なポインタ型です。Goの型システムを迂回して、任意のメモリ位置を指すことができます。主にランタイムや低レベルな操作で使用されます。uintptr
: ポインタを整数として表現する型です。ポインタ演算を行う際に使用されることがありますが、GCによって追跡されないため、GC対象のメモリを指す場合には注意が必要です。
- Goコンパイラ (
gc
) とリンカ (ld
):gc
(Go Compiler): Goのソースコードをコンパイルし、オブジェクトファイルを生成します。この過程で、型情報も生成され、バイナリに埋め込まれます。ld
(Go Linker): オブジェクトファイルをリンクして実行可能ファイルを生成します。この際、型情報やデバッグ情報(DWARF)なども適切に配置されます。- DWARF: Unix系システムで広く使われているデバッグ情報フォーマットです。Goのリンカは、デバッグ時に変数や型の情報を参照できるように、DWARF形式でデバッグ情報を生成します。
技術的詳細
このコミットの主要な変更点は、Goの内部型情報構造体である commonType
に gc
フィールドを追加したことです。この変更は、コンパイラ、リンカ、Goのreflect
パッケージ、そしてGoランタイムのC言語部分にわたって整合性を保つように行われています。
具体的には、以下のファイルが変更されています。
-
src/cmd/gc/reflect.c
:- Goコンパイラの型情報生成部分です。
dcommontype
関数内で、commonType
構造体のメモリレイアウトが更新されています。 // gc
というコメントとともにot = duintptr(s, ot, 0);
という行が追加されています。これは、コンパイル時にgc
フィールドの領域を確保し、初期値としてゼロ(uintptr
型)を設定することを示しています。commonType
の構造体コメントも更新され、gc unsafe.Pointer
が追加されています。また、alg
フィールドの型が*uintptr
からunsafe.Pointer
に変更され、その前に_ uint8
というパディングバイトが追加されています。これは、alg
とgc
フィールドがunsafe.Pointer
型(ポインタサイズ)になったことによるアライメント調整や、将来的なフィールドの追加を見越した変更である可能性があります。
- Goコンパイラの型情報生成部分です。
-
src/cmd/ld/dwarf.c
:- GoリンカのDWARFデバッグ情報生成部分です。
CommonSize
定数の値が2*PtrSize + 5*PtrSize + 8
から2*PtrSize + 6*PtrSize + 8
に変更されています。PtrSize
はポインタのサイズ(32bitシステムでは4バイト、64bitシステムでは8バイト)を表します。この変更は、commonType
構造体のサイズがPtrSize
分だけ増加したことを正確に反映しており、これはgc
フィールド(unsafe.Pointer
またはuintptr
)が追加されたことによるものです。これにより、デバッグ情報が正しいオフセットで型情報を参照できるようになります。
-
src/pkg/reflect/type.go
:- Goの
reflect
パッケージにおけるcommonType
構造体のGo言語側の定義です。 gc uintptr // garbage collection data
というフィールドが追加されています。uintptr
はポインタを保持できる整数型であり、Goの型システムからはGCの対象として直接追跡されませんが、ランタイム内部ではポインタとして扱われる可能性があります。
- Goの
-
src/pkg/runtime/type.go
:- Goランタイムにおける
commonType
構造体のGo言語側の定義です。 gc unsafe.Pointer
というフィールドが追加されています。unsafe.Pointer
は、Goの型システムを迂回して任意のメモリ位置を指すことができるため、ランタイムの低レベルな操作に適しています。alg
フィールドの型も*uintptr
からunsafe.Pointer
に変更されています。これは、alg
フィールドもまた、GCが直接追跡しないが、ランタイムが内部的にポインタとして扱うデータであることを示唆しています。
- Goランタイムにおける
-
src/pkg/runtime/type.h
:- GoランタイムのC言語部分で使用される
CommonType
構造体の定義です。 void *gc;
というフィールドが追加されています。C言語のvoid *
は、任意の型のポインタを指すことができる汎用ポインタであり、Goのunsafe.Pointer
に対応します。
- GoランタイムのC言語部分で使用される
これらの変更は、Goの型情報がコンパイラ、リンカ、Goのreflect
パッケージ、そしてランタイムのC言語部分で一貫して扱われるように、複数のレイヤーにわたって調整されていることを示しています。gc
フィールドは、GoのGCが型固有の情報を利用して、より効率的または高度なメモリ管理を行うための基盤を構築するものです。
コアとなるコードの変更箇所
src/cmd/gc/reflect.c
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -546,15 +546,17 @@ dcommontype(Sym *s, int ot, Type *t)
// ../../pkg/reflect/type.go:/^type.commonType
// actual type structure
// type commonType struct {
- // size uintptr;
- // hash uint32;
- // alg uint8;
- // align uint8;
- // fieldAlign uint8;
- // kind uint8;
- // string *string;
- // *extraType;
- // ptrToThis *Type
+ // size uintptr
+ // hash uint32
+ // _ uint8
+ // align uint8
+ // fieldAlign uint8
+ // kind uint8
+ // alg unsafe.Pointer
+ // gc unsafe.Pointer
+ // string *string
+ // *extraType
+ // ptrToThis *Type
// }
ot = duintptr(s, ot, t->width);
ot = duint32(s, ot, typehash(t));
@@ -579,6 +581,7 @@ dcommontype(Sym *s, int ot, Type *t)
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
else
ot = dsymptr(s, ot, algsym, 0);
+ ot = duintptr(s, ot, 0); // gc
p = smprint("%-uT", t);
//print("dcommontype: %s\n", p);
ot = dgostringptr(s, ot, p); // string
src/cmd/ld/dwarf.c
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -775,7 +775,7 @@ enum {
KindNoPointers = 1<<7,
// size of Type interface header + CommonType structure.
- CommonSize = 2*PtrSize+ 5*PtrSize + 8,
+ CommonSize = 2*PtrSize+ 6*PtrSize + 8,
};
static Reloc*
src/pkg/reflect/type.go
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -244,6 +244,7 @@ type commonType struct {
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
+ gc uintptr // garbage collection data
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *runtimeType // pointer to this type, if used in binary or has methods
src/pkg/runtime/type.go
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -21,7 +21,8 @@ type commonType struct {
align uint8
fieldAlign uint8
kind uint8
- alg *uintptr
+ alg unsafe.Pointer
+ gc unsafe.Pointer
string *string
*uncommonType
ptrToThis *interface{}
src/pkg/runtime/type.h
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -28,6 +28,7 @@ struct CommonType
uint8 fieldAlign;
uint8 kind;
Alg *alg;
+ void *gc;
String *string;
UncommonType *x;
Type *ptrto;
コアとなるコードの解説
src/cmd/gc/reflect.c
の変更
このファイルはGoコンパイラの一部であり、Goの型情報をバイナリに埋め込む際の処理を定義しています。
dcommontype
関数は、commonType
構造体の各フィールドをバイナリに書き込む役割を担っています。
追加された ot = duintptr(s, ot, 0); // gc
の行は、gc
フィールドのためにポインタサイズの領域を確保し、その値をゼロで初期化しています。これは、このフィールドがまだ使用されていないことを示しています。
コメントブロックの変更は、Goのreflect
パッケージで定義されているcommonType
のGo言語側の構造体定義を反映しており、gc unsafe.Pointer
が追加されたこと、およびalg
フィールドの型がunsafe.Pointer
に変更されたことを示しています。また、_ uint8
というパディングバイトが追加されている点も注目に値します。
src/cmd/ld/dwarf.c
の変更
このファイルはGoリンカの一部であり、生成される実行可能ファイルにデバッグ情報(DWARF)を埋め込む際の処理を定義しています。
CommonSize
定数は、Type
インターフェースヘッダとCommonType
構造体の合計サイズを定義しています。この値が 5*PtrSize
から 6*PtrSize
に変更されたことは、commonType
構造体のサイズがポインタ1つ分(PtrSize
)増加したことを明確に示しています。これは、gc
フィールドがポインタサイズであることを裏付けています。この変更により、デバッグツールがGoの型情報を正しく解釈できるようになります。
src/pkg/reflect/type.go
の変更
このファイルはGoの標準ライブラリreflect
パッケージの一部であり、Goプログラムが実行時に型情報を扱うためのGo言語側の定義を提供しています。
type commonType struct { ... }
の定義に gc uintptr // garbage collection data
が追加されました。uintptr
はポインタを整数として扱う型であり、Goの型システムからはGCの対象として直接追跡されません。これは、このフィールドがGCの内部的なメタデータを格納するために使用され、Goの通常のポインタとは異なる方法で扱われる可能性があることを示唆しています。
src/pkg/runtime/type.go
の変更
このファイルはGoランタイムのGo言語側の定義であり、Goの低レベルな動作を制御する部分です。
type commonType struct { ... }
の定義に gc unsafe.Pointer
が追加されました。unsafe.Pointer
は、Goの型システムを迂回して任意のメモリ位置を指すことができるため、ランタイムの低レベルな操作に適しています。
また、alg
フィールドの型が *uintptr
から unsafe.Pointer
に変更されています。これは、alg
フィールドもまた、GCが直接追跡しないが、ランタイムが内部的にポインタとして扱うデータであることを示唆しています。この変更は、gc
フィールドの追加と合わせて、commonType
構造体内のポインタ関連フィールドの扱いを統一する意図があったのかもしれません。
src/pkg/runtime/type.h
の変更
このファイルはGoランタイムのC言語側のヘッダファイルであり、GoランタイムのC言語部分がGoの型情報を扱うための定義を提供しています。
struct CommonType { ... }
の定義に void *gc;
が追加されました。C言語のvoid *
は、任意の型のポインタを指すことができる汎用ポインタであり、Goのunsafe.Pointer
に対応します。これにより、C言語で書かれたランタイムコードがgc
フィールドにアクセスできるようになります。
これらの変更は、Goの型情報がコンパイラ、リンカ、Goのreflect
パッケージ、そしてランタイムのC言語部分で一貫して扱われるように、複数のレイヤーにわたって調整されていることを示しています。gc
フィールドは、GoのGCが型固有の情報を利用して、より効率的または高度なメモリ管理を行うための基盤を構築するものです。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/doc/
- Goの
reflect
パッケージ: https://pkg.go.dev/reflect - Goのランタイムソースコード: https://github.com/golang/go/tree/master/src/runtime
- Goのガベージコレクションに関する情報 (Go 1.0当時のGCはマーク&スイープでした): https://go.dev/doc/gc-guide
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージに記載されている
https://golang.org/cl/6255074
は、Gerritの変更リストへのリンクです。) - DWARF Debugging Standard: https://dwarfstd.org/
- Go 1.0 Release Notes: https://go.dev/doc/go1
- Goの
unsafe
パッケージ: https://pkg.go.dev/unsafe - Goの
uintptr
型: https://pkg.go.dev/builtin#uintptr - GoのGCの歴史と進化に関する記事 (一般的な情報源): GoのGCはGo 1.5で大きく変更されましたが、このコミットはそれ以前のGo 1.0時代の基盤構築の一部です。