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

[インデックス 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言語の内部構造に関する知識が必要です。

  1. Goランタイム (Go Runtime): Goプログラムは、OSの機能に直接依存するのではなく、Goランタイムと呼ばれる独自の実行環境上で動作します。ランタイムは、ゴルーチンのスケジューリング、メモリ管理(ガベージコレクションを含む)、チャネル通信など、Go言語の並行処理とメモリ安全性を実現するための低レベルな機能を提供します。
  2. ガベージコレクション (Garbage Collection, GC): Goは自動メモリ管理を採用しており、開発者が手動でメモリを解放する必要がありません。GCは、プログラムがもはや到達できない(参照されていない)メモリ領域を自動的に識別し、解放するプロセスです。GoのGCは、ヒープ上のオブジェクトをスキャンし、ポインタをたどって「生きている」オブジェクトを特定します。このスキャンには、各オブジェクトの型情報が不可欠です。
  3. 型情報 (Type Information): Goのランタイムは、プログラム内のすべての型に関するメタデータを持っています。このメタデータには、型のサイズ、アライメント、ハッシュ値、そして最も重要なこととして、その型がポインタを含むかどうか、またポインタがどこにあるかという情報が含まれます。この情報は、リフレクション(reflectパッケージ)やGCによって利用されます。
  4. reflectパッケージ: Goの標準ライブラリであるreflectパッケージは、実行時に型情報を検査・操作するための機能を提供します。このパッケージが扱う型情報は、ランタイム内部の型情報構造体(commonTypeなど)に基づいています。
  5. commonType構造体: Goのランタイムとreflectパッケージで使用される、すべてのGoの型が共通して持つ基本情報(サイズ、ハッシュ、種類など)を定義する内部構造体です。この構造体は、Goのソースコード(src/pkg/reflect/type.go, src/pkg/runtime/type.go)と、C言語で書かれたランタイム部分(src/pkg/runtime/type.h)の両方で定義され、コンパイラによって生成される型情報に影響を与えます。
  6. unsafe.Pointeruintptr:
    • unsafe.Pointer: 任意の型のポインタを保持できる特殊なポインタ型です。Goの型システムを迂回して、任意のメモリ位置を指すことができます。主にランタイムや低レベルな操作で使用されます。
    • uintptr: ポインタを整数として表現する型です。ポインタ演算を行う際に使用されることがありますが、GCによって追跡されないため、GC対象のメモリを指す場合には注意が必要です。
  7. Goコンパイラ (gc) とリンカ (ld):
    • gc (Go Compiler): Goのソースコードをコンパイルし、オブジェクトファイルを生成します。この過程で、型情報も生成され、バイナリに埋め込まれます。
    • ld (Go Linker): オブジェクトファイルをリンクして実行可能ファイルを生成します。この際、型情報やデバッグ情報(DWARF)なども適切に配置されます。
    • DWARF: Unix系システムで広く使われているデバッグ情報フォーマットです。Goのリンカは、デバッグ時に変数や型の情報を参照できるように、DWARF形式でデバッグ情報を生成します。

技術的詳細

このコミットの主要な変更点は、Goの内部型情報構造体である commonTypegc フィールドを追加したことです。この変更は、コンパイラ、リンカ、Goのreflectパッケージ、そしてGoランタイムのC言語部分にわたって整合性を保つように行われています。

具体的には、以下のファイルが変更されています。

  1. 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というパディングバイトが追加されています。これは、alggcフィールドがunsafe.Pointer型(ポインタサイズ)になったことによるアライメント調整や、将来的なフィールドの追加を見越した変更である可能性があります。
  2. 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)が追加されたことによるものです。これにより、デバッグ情報が正しいオフセットで型情報を参照できるようになります。
  3. src/pkg/reflect/type.go:

    • GoのreflectパッケージにおけるcommonType構造体のGo言語側の定義です。
    • gc uintptr // garbage collection data というフィールドが追加されています。uintptrはポインタを保持できる整数型であり、Goの型システムからはGCの対象として直接追跡されませんが、ランタイム内部ではポインタとして扱われる可能性があります。
  4. src/pkg/runtime/type.go:

    • GoランタイムにおけるcommonType構造体のGo言語側の定義です。
    • gc unsafe.Pointer というフィールドが追加されています。unsafe.Pointerは、Goの型システムを迂回して任意のメモリ位置を指すことができるため、ランタイムの低レベルな操作に適しています。
    • algフィールドの型も *uintptr から unsafe.Pointer に変更されています。これは、algフィールドもまた、GCが直接追跡しないが、ランタイムが内部的にポインタとして扱うデータであることを示唆しています。
  5. src/pkg/runtime/type.h:

    • GoランタイムのC言語部分で使用されるCommonType構造体の定義です。
    • void *gc; というフィールドが追加されています。C言語のvoid *は、任意の型のポインタを指すことができる汎用ポインタであり、Goのunsafe.Pointerに対応します。

これらの変更は、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が型固有の情報を利用して、より効率的または高度なメモリ管理を行うための基盤を構築するものです。

関連リンク

参考にした情報源リンク