[インデックス 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時代の基盤構築の一部です。