[インデックス 11832] ファイルの概要
このコミットは、Go言語のランタイムとunsafe
パッケージにおける型情報の扱いを大幅に変更し、reflect
パッケージへの一元化を進めるものです。具体的には、runtime
パッケージ内のType
型とその関連実装、およびunsafe
パッケージ内のTypeof
、Reflect
、Unreflect
、New
、NewArray
といった関数が削除され、これらがreflect
パッケージの機能に置き換えられました。
コミット
commit 6a75ece01c99164d04752f26d58fdfec268d9139
Author: Russ Cox <rsc@golang.org>
Date: Sun Feb 12 23:26:20 2012 -0500
runtime: delete Type and implementations (use reflect instead)
unsafe: delete Typeof, Reflect, Unreflect, New, NewArray
Part of issue 2955 and issue 2968.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5650069
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6a75ece01c99164d04752f26d58d9139
元コミット内容
Go言語のランタイムとunsafe
パッケージにおける型情報の扱いをreflect
パッケージに統合するため、以下の変更が行われました。
runtime
パッケージからType
型およびその関連実装を削除し、reflect
パッケージの機能を使用するように変更。unsafe
パッケージからTypeof
、Reflect
、Unreflect
、New
、NewArray
関数を削除。
この変更は、Go言語のIssue 2955と2968の一部として実施されました。
変更の背景
このコミットの主な背景には、Go言語の型システムとリフレクションメカニズムの設計思想の進化があります。初期のGo言語では、型情報はruntime
パッケージ内で直接管理され、unsafe
パッケージを通じて低レベルな型操作が可能でした。しかし、これはいくつかの問題を引き起こしていました。
- 機能の重複と複雑性:
runtime
パッケージとreflect
パッケージの両方に型情報に関する機能が分散しており、コードベースの複雑性を増していました。特に、unsafe
パッケージの関数はreflect
パッケージが提供する機能と重複しており、より安全で堅牢なreflect
パッケージの存在意義を薄めていました。 - 安全性と堅牢性:
unsafe
パッケージは、その名の通り「安全でない」操作を可能にするものであり、誤用するとプログラムのクラッシュや未定義の動作を引き起こす可能性がありました。型情報のような重要な要素をunsafe
パッケージで直接操作できることは、Go言語が目指す安全性と堅牢性とは相容れない側面がありました。 - ブートストラップとパッケージ依存関係の簡素化: コミットメッセージにもあるように、
reflect
パッケージがすべてのバイナリに自動的にリンクされる必要がないようにすることで、ブートストラッププロセスとパッケージ依存関係を簡素化する狙いがありました。runtime
パッケージが型情報を直接持つことで、reflect
パッケージがruntime
パッケージの内部構造に依存するという循環的な依存関係が生じる可能性がありました。
これらの問題を解決し、Go言語の型システムをより一貫性があり、安全で、保守しやすいものにするために、型情報の管理をreflect
パッケージに一元化する決定がなされました。これにより、runtime
パッケージはより低レベルなランタイムの責務に集中し、型情報の検査と操作はreflect
パッケージを通じて安全に行われるようになります。
前提知識の解説
このコミットを理解するためには、Go言語のリフレクション、unsafe
パッケージ、およびGoの型システムに関する基本的な知識が必要です。
Go言語のリフレクション (reflect
パッケージ)
Go言語のreflect
パッケージは、実行時にプログラムの構造を検査し、操作するための機能を提供します。これにより、型情報(reflect.Type
)や値(reflect.Value
)を動的に取得・変更することが可能になります。
reflect.Type
: Goの型を表すインターフェースです。型の名前、カテゴリ(Kind
)、メソッド、フィールドなどの情報を取得できます。reflect.TypeOf(i interface{})
関数で取得します。reflect.Value
: Goの値を表す構造体です。値の取得、設定、メソッドの呼び出しなど、値に対する操作が可能です。reflect.ValueOf(i interface{})
関数で取得します。reflect.Kind
: 型の基本的なカテゴリ(例:int
,string
,struct
,slice
,map
,ptr
など)を表す列挙型です。reflect.Type
やreflect.Value
からKind()
メソッドで取得できます。
リフレクションは、汎用的なデータシリアライゼーション(例: JSONエンコーディング/デコーディング)、ORM、テストフレームワークなど、コンパイル時に型が確定しない状況で非常に強力なツールとなります。
unsafe
パッケージ
unsafe
パッケージは、Go言語の型安全性をバイパスし、低レベルなメモリ操作を可能にするためのパッケージです。ポインタ演算や、異なる型間のポインタ変換など、通常では許可されない操作を行うことができます。
unsafe.Pointer
: 任意の型のポインタを保持できる特殊なポインタ型です。C言語のvoid*
に似ていますが、Goのガベージコレクタと連携して動作します。unsafe.Sizeof
: 型または変数のメモリサイズをバイト単位で返します。unsafe.Alignof
: 型または変数のアライメントをバイト単位で返します。unsafe.Offsetof
: 構造体内のフィールドのオフセットをバイト単位で返します。
unsafe
パッケージは非常に強力ですが、その使用は厳密に制限されるべきです。なぜなら、型安全性を損ない、移植性のないコードやバグの原因となる可能性があるためです。通常、Goの標準ライブラリや、特定のパフォーマンス要件を持つ低レベルなコードでのみ使用されます。
Goの型システムとインターフェースの内部表現
Goのインターフェースは、内部的には2つのワードで表現されます。
- 型情報ポインタ (Type Word): インターフェースが保持する具体的な値の型情報へのポインタです。この型情報には、型のサイズ、アライメント、メソッドセットなどが含まれます。
- データポインタ (Data Word): インターフェースが保持する具体的な値へのポインタです。値がポインタサイズに収まる場合は直接値が格納されることもあります。
このコミット以前は、runtime
パッケージがこの型情報を直接管理し、unsafe
パッケージがその内部構造にアクセスして型操作を行うための関数を提供していました。しかし、この変更により、型情報の管理と操作はreflect
パッケージに集約され、より抽象化された安全なAPIを通じて行われるようになります。
技術的詳細
このコミットの技術的な核心は、Goの型システムにおける「真の型情報源」をruntime
パッケージからreflect
パッケージへ移行した点にあります。
runtime.Type
の廃止とreflect.Type
への統一
以前のGoでは、runtime
パッケージ内にType
という型が存在し、これがGoの型の内部表現を担っていました。しかし、このコミットにより、runtime/type.go
からType
インターフェースおよびcommonType
、_method
、_imethod
などの型定義が削除されました。代わりに、reflect/type.go
に定義されているreflect.Type
インターフェースと、その基盤となるcommonType
構造体が、Goの型情報の唯一の公式な表現となりました。
これにより、runtime
パッケージは型情報の詳細な構造を知る必要がなくなり、reflect
パッケージが型情報の定義と操作の責任を完全に負うことになります。これは、Goのモジュール間の責務分離を明確にし、コードベースの凝集度を高める上で重要な変更です。
unsafe
パッケージ関数の削除とreflect
パッケージへの移行
unsafe
パッケージから削除された関数とその代替は以下の通りです。
unsafe.Typeof(i interface{}) (typ interface{})
:- 削除理由:
reflect.TypeOf(i interface{}) Type
と機能が重複しており、reflect.TypeOf
の方がより安全で、reflect.Type
という適切な型を返すため。 - 代替:
reflect.TypeOf(i)
- 削除理由:
unsafe.Reflect(e Eface, rettype Eface, retaddr unsafe.Pointer)
:- 削除理由: インターフェースの内部表現を直接操作する低レベルな関数であり、
reflect.ValueOf
やreflect.NewAt
などのより抽象化された安全なAPIで代替可能であるため。 - 代替:
reflect.ValueOf(i)
や、特定のメモリ位置にreflect.Value
を作成するreflect.NewAt(typ Type, p unsafe.Pointer)
。
- 削除理由: インターフェースの内部表現を直接操作する低レベルな関数であり、
unsafe.Unreflect(typ Eface, addr unsafe.Pointer, e Eface)
:- 削除理由:
unsafe.Reflect
の逆操作であり、同様に低レベルな操作であるため。 - 代替:
reflect.NewAt(typ, p).Elem()
など、reflect.Value
を介した操作。
- 削除理由:
unsafe.New(typ Eface, ret unsafe.Pointer)
:- 削除理由:
reflect.New(typ Type) Value
と機能が重複しており、reflect.New
の方がreflect.Value
を返すため、よりGoらしいAPIであるため。 - 代替:
reflect.New(typ)
- 削除理由:
unsafe.NewArray(typ Eface, n uint32, ret unsafe.Pointer)
:- 削除理由:
reflect.MakeSlice(typ Type, len, cap int) Value
と機能が重複しており、reflect.MakeSlice
の方がスライスを直接作成できるため、よりGoらしいAPIであるため。 - 代替:
reflect.MakeSlice(typ, n, n)
- 削除理由:
これらの変更により、Goの型システムとリフレクションに関する操作は、すべてreflect
パッケージの公開APIを通じて行われることが推奨されるようになりました。これにより、Goプログラムの安全性と保守性が向上します。
reflect
パッケージの内部構造の調整
reflect/type.go
では、runtime.Type
への参照が*runtimeType
(interface{}
のエイリアス)に変更され、commonType
構造体内のポインタ型も*runtime.Type
から*runtimeType
に更新されました。これは、reflect
パッケージがruntime
パッケージの具体的な型定義に直接依存するのではなく、より抽象的なinterface{}
を介して型情報を扱うようにするための変更です。
また、reflect
パッケージ内の各種型(arrayType
, chanType
, funcType
, interfaceType
, mapType
, ptrType
, sliceType
, structField
)の要素型も、*runtime.Type
から*runtimeType
に変更されています。これにより、reflect
パッケージは自身の内部で型情報を完結させ、runtime
パッケージとの結合度を低減しています。
encoding/gob
パッケージの変更
encoding/gob
パッケージは、Goのデータ構造をシリアライズ/デシリアライズするためのパッケージであり、内部でリフレクションを多用しています。このコミットでは、unsafe
パッケージの関数が削除されたことに伴い、gob/decode.go
とgob/encode.go
内のunsafe.New
、unsafe.NewArray
、unsafe.Unreflect
の呼び出しが、それぞれreflect.New
、reflect.MakeSlice
、reflect.NewAt
などのreflect
パッケージの関数に置き換えられました。
これは、unsafe
パッケージの低レベルな操作からreflect
パッケージのより安全で抽象化されたAPIへの移行を示す具体的な例です。
runtime/error.go
とruntime/iface.c
の変更
runtime/error.go
では、TypeAssertionError
構造体からType
型のフィールド(interfaceType
, concreteType
, assertedType
)が削除され、代わりにstring
型のフィールド(interfaceString
, concreteString
, assertedString
)が使用されるようになりました。これは、エラー情報が文字列として表現されることで、runtime
パッケージがreflect.Type
の具体的な構造に依存しないようにするための変更です。
runtime/iface.c
では、インターフェースの型アサーションに関連するエラー生成関数runtime·newTypeAssertionError
の引数からType*
型のポインタが削除され、String*
型のポインタのみを受け取るように変更されました。また、unsafe.Typeof
、unsafe.Reflect
、unsafe.Unreflect
、unsafe.New
、unsafe.NewArray
のC言語実装が削除され、代わりにreflect·unsafe_Typeof
などの新しい関数名が導入されています。これは、これらの関数がreflect
パッケージの内部実装として扱われるようになったことを示唆しています。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は、以下のファイルに集中しています。
src/pkg/reflect/type.go
:runtime.Type
への依存を排除し、reflect
パッケージが型情報の主要な定義元となるように変更。commonType
構造体や、各種型(arrayType
など)の要素型が*runtime.Type
から*runtimeType
(interface{}
のエイリアス)に変更されています。src/pkg/reflect/value.go
:unsafe
パッケージの関数呼び出しをreflect
パッケージの関数に置き換え。特にMakeSlice
、New
、NewAt
などの関数が追加・修正されています。src/pkg/runtime/type.go
:Type
インターフェースおよび関連する型定義が完全に削除され、このファイルがGoのデバッガ(gdb)のためのDWARF情報を提供する目的のみに特化されました。src/pkg/runtime/iface.c
: インターフェースの型アサーションに関連するC言語コードから、unsafe
パッケージの関数呼び出しが削除され、reflect
パッケージの内部関数への参照に置き換えられています。src/pkg/encoding/gob/decode.go
&src/pkg/encoding/gob/encode.go
:unsafe.New
、unsafe.NewArray
、unsafe.Unreflect
の呼び出しが、reflect.New
、reflect.MakeSlice
、reflect.NewAt
などのreflect
パッケージの関数に置き換えられています。src/pkg/unsafe/unsafe.go
:Typeof
,Reflect
,Unreflect
,New
,NewArray
の宣言が削除されています。
コアとなるコードの解説
src/pkg/reflect/type.go
の変更
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -16,7 +16,6 @@
package reflect
import (
- "runtime"
"strconv"
"sync"
"unsafe"
@@ -181,7 +180,7 @@ type Type interface {
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type
- runtimeType() *runtime.Type
+ runtimeType() *runtimeType
common() *commonType
uncommon() *uncommonType
}
@@ -221,128 +220,131 @@ const (
)
/*
- * Copy of data structures from ../runtime/type.go.
- * For comments, see the ones in that file.
- *\
- * These data structures are known to the compiler and the runtime.\
- *\
- * Putting these types in runtime instead of reflect means that
- * reflect doesn\'t need to be autolinked into every binary, which
- * simplifies bootstrapping and package dependencies.
- * Unfortunately, it also means that reflect needs its own
- * copy in order to access the private fields.
+ * These data structures are known to the compiler (../../cmd/gc/reflect.c).
+ * A few are known to ../runtime/type.go to convey to debuggers.
*/
+// The compiler can only construct empty interface values at
+// compile time; non-empty interface values get created
+// during initialization. Type is an empty interface
+// so that the compiler can lay out references as data.
+// The underlying type is *reflect.ArrayType and so on.
+type runtimeType interface{}
+
// commonType is the common implementation of most values.
// It is embedded in other, public struct types, but always
// with a unique tag like `reflect:\"array\"` or `reflect:\"ptr\"`
// so that code cannot convert from, say, *arrayType to *ptrType.
-
type commonType struct {
- size uintptr
- hash uint32
- _ uint8
- align uint8
- fieldAlign uint8
- kind uint8
- alg *uintptr
- string *string
- *uncommonType
- ptrToThis *runtime.Type
+ size uintptr // size in bytes
+ hash uint32 // hash of type; avoids computation in hash tables
+ _ uint8 // unused/padding
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ kind uint8 // enumeration for C
+ alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
+ 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
}
+// Method on non-interface type
type method struct {
- name *string
- pkgPath *string
- mtyp *runtime.Type
- typ *runtime.Type
- ifn unsafe.Pointer
- tfn unsafe.Pointer
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ mtyp *runtimeType // method type (without receiver)
+ typ *runtimeType // .(*FuncType) underneath (with receiver)
+ ifn unsafe.Pointer // fn used in interface call (one-word receiver)
+ tfn unsafe.Pointer // fn used for normal method call
}
+// uncommonType is present only for types with names or methods
+// (if T is a named type, the uncommonTypes for T and *T have methods).
+// Using a pointer to this struct reduces the overall size required
+// to describe an unnamed type with no methods.
type uncommonType struct {
- name *string
- pkgPath *string
- methods []method
+ name *string // name of type
+ pkgPath *string // import path; nil for built-in types like int, string
+ methods []method // methods associated with type
}
// ChanDir represents a channel type\'s direction.
type ChanDir int
const (
- RecvDir ChanDir = 1 << iota
- SendDir
- BothDir = RecvDir | SendDir
+ RecvDir ChanDir = 1 << iota // <-chan
+ SendDir // chan<-
+ BothDir = RecvDir | SendDir // chan
)
// arrayType represents a fixed array type.
type arrayType struct {
commonType `reflect:\"array\"`
- elem *runtime.Type
- slice *runtime.Type
+ elem *runtimeType // array element type
+ slice *runtimeType // slice type
len uintptr
}
// chanType represents a channel type.
type chanType struct {
commonType `reflect:\"chan\"`
- elem *runtime.Type
- dir uintptr
+ elem *runtimeType // channel element type
+ dir uintptr // channel direction (ChanDir)
}
// funcType represents a function type.
type funcType struct {
commonType `reflect:\"func\"`
- dotdotdot bool
- in []*runtime.Type
- out []*runtime.Type
+ dotdotdot bool // last input parameter is ...
+ in []*runtimeType // input parameter types
+ out []*runtimeType // output parameter types
}
// imethod represents a method on an interface type
type imethod struct {
- name *string
- pkgPath *string
- typ *runtime.Type
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *runtimeType // .(*FuncType) underneath
}
// interfaceType represents an interface type.
type interfaceType struct {
commonType `reflect:\"interface\"`
- methods []imethod
+ methods []imethod // sorted by hash
}
// mapType represents a map type.
type mapType struct {
commonType `reflect:\"map\"`
- key *runtime.Type
- elem *runtime.Type
+ key *runtimeType // map key type
+ elem *runtimeType // map element (value) type
}
// ptrType represents a pointer type.
type ptrType struct {
commonType `reflect:\"ptr\"`
- elem *runtime.Type
+ elem *runtimeType // pointer element (pointed at) type
}
// sliceType represents a slice type.
type sliceType struct {
commonType `reflect:\"slice\"`
- elem *runtime.Type
+ elem *runtimeType // slice element type
}
// Struct field
type structField struct {
- name *string
- pkgPath *string
- typ *runtime.Type
- tag *string
- offset uintptr
+ name *string // nil for embedded fields
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *runtimeType // type of field
+ tag *string // nil if no tag
+ offset uintptr // byte offset of field within struct
}
// structType represents a struct type.
type structType struct {
commonType `reflect:\"struct\"`
- fields []structField
+ fields []structField // sorted by offset
}
/*
@@ -909,23 +911,18 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (f StructField, pr\
}\n \n // Convert runtime type to reflect type.\n-func toCommonType(p *runtime.Type) *commonType {\n+func toCommonType(p *runtimeType) *commonType {\n if p == nil {\n return nil\n }\n-\ttype hdr struct {\n-\t\tx interface{}\n-\t\tt commonType\n-\t}\n-\tx := unsafe.Pointer(p)\n-\treturn &(*hdr)(x).t\n+\treturn (*p).(*commonType)\n }\n \n-func toType(p *runtime.Type) Type {\n+func toType(p *runtimeType) Type {\n if p == nil {\n return nil\n }\n-\treturn toCommonType(p).toType()\n+\treturn (*p).(*commonType)\n }\n \n // TypeOf returns the reflection Type of the value in the interface{}.\n@@ -940,14 +937,14 @@ var ptrMap struct {\n m map[*commonType]*ptrType\n }\n \n-func (t *commonType) runtimeType() *runtime.Type {\n-\t// The runtime.Type always precedes the commonType in memory.\n+func (t *commonType) runtimeType() *runtimeType {\n+\t// The runtimeType always precedes the commonType in memory.\n // Adjust pointer to find it.\n var rt struct {\n-\t\ti runtime.Type\n+\t\ti runtimeType\n \tct commonType\n }\n-\treturn (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))\n+\treturn (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))\n }\n \n // PtrTo returns the pointer type with element t.\n@@ -986,16 +983,15 @@ func (ct *commonType) ptrTo() *commonType {\n }\n \n var rt struct {\n-\t\ti runtime.Type\n+\t\ti runtimeType\n \tptrType\n }\n-\trt.i = (*runtime.PtrType)(unsafe.Pointer(&rt.ptrType))\n+\trt.i = &rt.commonType\n \n // initialize p using *byte\'s ptrType as a prototype.\n-\t// have to do assignment as ptrType, not runtime.PtrType,\n-\t// in order to write to unexported fields.\n \tp = &rt.ptrType\n-\tbp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))\n+\tvar ibyte interface{} = (*byte)(nil)\n+\tbp := (*ptrType)(unsafe.Pointer((**(**runtimeType)(unsafe.Pointer(&ibyte))).(*commonType)))\n \t*p = *bp\n \n \ts := \"*\" + *ct.string\n@@ -1010,7 +1006,7 @@ func (ct *commonType) ptrTo() *commonType {\n \n \tp.uncommonType = nil\n \tp.ptrToThis = nil\n-\tp.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))\n+\tp.elem = (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))\n \n \tptrMap.m[ct] = p\n \tptrMap.Unlock()\n```
- **`import "runtime"`の削除**: `reflect`パッケージが`runtime`パッケージの具体的な型定義に直接依存しなくなったことを示します。
- **`runtimeType interface{}`の導入**: `reflect`パッケージ内で、ランタイムの型情報を抽象的に扱うための`interface{}`エイリアスが導入されました。これにより、`reflect`パッケージは`runtime`パッケージの内部実装に直接結合されることなく、型情報を参照できるようになります。
- **`commonType`および関連構造体のポインタ型の変更**: `commonType`、`method`、`imethod`、`arrayType`、`chanType`、`funcType`、`interfaceType`、`mapType`、`ptrType`、`sliceType`、`structField`内の`*runtime.Type`型のフィールドがすべて`*runtimeType`(`interface{}`のエイリアス)に変更されました。これは、`reflect`パッケージが型情報の定義と操作の主要な責任を負うようになったことを明確に示しています。
- **`toCommonType`、`toType`、`runtimeType()`メソッドの変更**: これらの関数やメソッドは、`*runtime.Type`から`*runtimeType`への変換ロジックを調整し、`reflect`パッケージが型情報をより適切に扱うように変更されました。特に`toCommonType`は、`unsafe.Pointer`を使った複雑なポインタ操作から、より直接的な型アサーションに簡素化されています。
### `src/pkg/reflect/value.go`の変更
```diff
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -1606,6 +1606,10 @@ func Copy(dst, src Value) int {\n * constructors\n */\n \n+// implemented in package runtime\n+func unsafe_New(Type) unsafe.Pointer
+func unsafe_NewArray(Type, int) unsafe.Pointer
+\n // MakeSlice creates a new zero-initialized slice value\n // for the specified slice type, length, and capacity.\n func MakeSlice(typ Type, len, cap int) Value {\n@@ -1618,7 +1618,7 @@ func MakeSlice(typ Type, len, cap int) Value {\n \n // Reinterpret as *SliceHeader to edit.\n s := (*SliceHeader)(unsafe.Pointer(&x))\n-\ts.Data = uintptr(unsafe.NewArray(typ.Elem(), cap))\n+\ts.Data = uintptr(unsafe_NewArray(typ.Elem(), cap))\n \ts.Len = len\n \ts.Cap = cap\n \n@@ -1697,7 +1701,7 @@ func Zero(typ Type) Value {\n if t.size <= ptrSize {\n return Value{t, nil, fl}\n }\n-\treturn Value{t, unsafe.New(typ), fl | flagIndir}\n+\treturn Value{t, unsafe_New(typ), fl | flagIndir}\n }\n \n // New returns a Value representing a pointer to a new zero value\n@@ -1706,11 +1710,18 @@ func New(typ Type) Value {\n if typ == nil {\n panic(\"reflect: New(nil)\")\n }\n-\tptr := unsafe.New(typ)\n+\tptr := unsafe_New(typ)\n \tfl := flag(Ptr) << flagKindShift\n \treturn Value{typ.common().ptrTo(), ptr, fl}\n }\n \n+// NewAt returns a Value representing a pointer to a value of the\n+// specified type, using p as that pointer.\n+func NewAt(typ Type, p unsafe.Pointer) Value {\n+\tfl := flag(Ptr) << flagKindShift\n+\treturn Value{typ.common().ptrTo(), p, fl}\n+}\n+\n // assignTo returns a value v that can be assigned directly to typ.\n // It panics if v is not assignable to typ.\n // For a conversion to an interface type, target is a suggested scratch space to use.\n@@ -1749,20 +1760,20 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va\n func chancap(ch iword) int32\n func chanclose(ch iword)\n func chanlen(ch iword) int32\n-func chanrecv(t *runtime.Type, ch iword, nb bool) (val iword, selected, received bool)\n-func chansend(t *runtime.Type, ch iword, val iword, nb bool) bool\n-\n-func makechan(typ *runtime.Type, size uint32) (ch iword)\n-func makemap(t *runtime.Type) (m iword)\n-func mapaccess(t *runtime.Type, m iword, key iword) (val iword, ok bool)\n-func mapassign(t *runtime.Type, m iword, key, val iword, ok bool)\n-func mapiterinit(t *runtime.Type, m iword) *byte\n+func chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool)\n+func chansend(t *runtimeType, ch iword, val iword, nb bool) bool\n+\n+func makechan(typ *runtimeType, size uint32) (ch iword)\n+func makemap(t *runtimeType) (m iword)\n+func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool)\n+func mapassign(t *runtimeType, m iword, key, val iword, ok bool)\n+func mapiterinit(t *runtimeType, m iword) *byte\n func mapiterkey(it *byte) (key iword, ok bool)\n func mapiternext(it *byte)\n func maplen(m iword) int32\n \n func call(fn, arg unsafe.Pointer, n uint32)\n-func ifaceE2I(t *runtime.Type, src interface{}, dst unsafe.Pointer)\n+func ifaceE2I(t *runtimeType, src interface{}, dst unsafe.Pointer)\n \n // Dummy annotation marking that the value x escapes,\n // for use in cases where the reflect code is so clever that\n```
- **`unsafe_New`と`unsafe_NewArray`の宣言**: `reflect`パッケージ内で、ランタイムが提供する低レベルなメモリ割り当て関数を呼び出すための内部関数として宣言されています。これは、`unsafe`パッケージの公開関数が削除された後も、`reflect`パッケージが内部的にこれらの機能を利用できるようにするためのものです。
- **`MakeSlice`、`Zero`、`New`関数での`unsafe`関数の置き換え**: `MakeSlice`、`Zero`、`New`といった`reflect`パッケージのコンストラクタ関数内で、以前は`unsafe.NewArray`や`unsafe.New`を直接呼び出していた箇所が、新しく宣言された内部関数`unsafe_NewArray`や`unsafe_New`に置き換えられています。これにより、`reflect`パッケージの外部からは`unsafe`パッケージの直接的な利用が見えなくなります。
- **`NewAt`関数の追加**: 特定のメモリ位置に`reflect.Value`を作成するための`NewAt`関数が追加されました。これは、以前`unsafe.Unreflect`が提供していた機能の一部を、より安全な形で代替するものです。
- **ランタイム関数シグネチャの変更**: `chanrecv`、`chansend`、`makechan`、`makemap`、`mapaccess`、`mapassign`、`mapiterinit`、`ifaceE2I`などのランタイム関数の引数型が`*runtime.Type`から`*runtimeType`に変更されています。これは、`reflect`パッケージがランタイムとのインターフェースを`runtimeType`という抽象的な型で統一したことを示しています。
### `src/pkg/runtime/type.go`の変更
```diff
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -4,206 +4,51 @@
/*
* Runtime type representation.\
- *\
- * The following files know the exact layout of these\
- * data structures and must be kept in sync with this file:\
- *\
- *\t../../cmd/gc/reflect.c\
- *\t../../cmd/ld/dwarf.c decodetype_*\
- *\t../reflect/type.go\
- *\ttype.h
+ * This file exists only to provide types that 6l can turn into\
+ * DWARF information for use by gdb. Nothing else uses these.\
+ * They should match the same types in ../reflect/type.go.\
+ * For comments see ../reflect/type.go.\
*/
package runtime
import "unsafe"
-// The compiler can only construct empty interface values at
-// compile time; non-empty interface values get created
-// during initialization. Type is an empty interface
-// so that the compiler can lay out references as data.
-type Type interface{}
-// All types begin with a few common fields needed for
-// the interface runtime.
type commonType struct {\n-\tsize uintptr // size in bytes\n-\thash uint32 // hash of type; avoids computation in hash tables\n-\t_ uint8 // unused\n-\talign uint8 // alignment of variable with this type\n-\tfieldAlign uint8 // alignment of struct field with this type\n-\tkind uint8 // enumeration for C\n-\talg *uintptr // algorithm table (../runtime/runtime.h:/Alg)\n-\tstring *string // string form; unnecessary but undeniably useful\n-\t*uncommonType // (relatively) uncommon fields\n-\tptrToThis *Type // pointer to this type, if used in binary or has methods\n+\tsize uintptr\n+\thash uint32\n+\t_ uint8\n+\talign uint8\n+\tfieldAlign uint8\n+\tkind uint8\n+\talg *uintptr\n+\tstring *string\n+\t*uncommonType\n+\tptrToThis *interface{}\n }\n
-// Values for commonType.kind.\n-const (\n-\tkindBool = 1 + iota\n-\tkindInt\n-\tkindInt8\n-\tkindInt16\n-\tkindInt32\n-\tkindInt64\n-\tkindUint\n-\tkindUint8\n-\tkindUint16\n-\tkindUint32\n-\tkindUint64\n-\tkindUintptr\n-\tkindFloat32\n-\tkindFloat64\n-\tkindComplex64\n-\tkindComplex128\n-\tkindArray\n-\tkindChan\n-\tkindFunc\n-\tkindInterface\n-\tkindMap\n-\tkindPtr\n-\tkindSlice\n-\tkindString\n-\tkindStruct\n-\tkindUnsafePointer\n-\n-\tkindNoPointers = 1 << 7 // OR\'ed into kind\n-)\n-\n-// Method on non-interface type\n-type _method struct { // underscore is to avoid collision with C\n-\tname *string // name of method\n-\tpkgPath *string // nil for exported Names; otherwise import path\n-\tmtyp *Type // method type (without receiver)\n-\ttyp *Type // .(*FuncType) underneath (with receiver)\n-\tifn unsafe.Pointer // fn used in interface call (one-word receiver)\n-\ttfn unsafe.Pointer // fn used for normal method call\n+\n+type _method struct {\n+\tname *string\n+\tpkgPath *string\n+\tmtyp *interface{}\n+\ttyp *interface{}\n+\tifn unsafe.Pointer\n+\ttfn unsafe.Pointer\n }\n
-// uncommonType is present only for types with names or methods\n-// (if T is a named type, the uncommonTypes for T and *T have methods).\n-// Using a pointer to this struct reduces the overall size required\n-// to describe an unnamed type with no methods.\n type uncommonType struct {\n-\tname *string // name of type\n-\tpkgPath *string // import path; nil for built-in types like int, string\n-\tmethods []_method // methods associated with type\n+\tname *string\n+\tpkgPath *string\n+\tmethods []_method\n }\n
-// BoolType represents a boolean type.\n-type BoolType commonType\n-// FloatType represents a float type.\n-type FloatType commonType
-// ComplexType represents a complex type.\n-type ComplexType commonType
-// IntType represents an int type.\n-type IntType commonType
-// UintType represents a uint type.\n-type UintType commonType
-// StringType represents a string type.\n-type StringType commonType
-// UintptrType represents a uintptr type.\n-type UintptrType commonType
-// UnsafePointerType represents an unsafe.Pointer type.\n-type UnsafePointerType commonType
-// ArrayType represents a fixed array type.\n-type ArrayType struct {\n-\tcommonType\n-\telem *Type // array element type\n-\tslice *Type // slice type\n-\tlen uintptr\n-}\n-// SliceType represents a slice type.\n-type SliceType struct {\n-\tcommonType\n-\telem *Type // slice element type\n-}\n-// ChanDir represents a channel type\'s direction.\n-type ChanDir int
-// const (\n-//\tRecvDir ChanDir = 1 << iota // <-chan\n-//\tSendDir // chan<-\n-//\tBothDir = RecvDir | SendDir // chan\n-//)\n-// ChanType represents a channel type.\n-type ChanType struct {\n-\tcommonType\n-\telem *Type // channel element type\n-\tdir uintptr // channel direction (ChanDir)\n-}\n-// FuncType represents a function type.\n-type FuncType struct {\n-\tcommonType\n-\tdotdotdot bool // last input parameter is ...\n-\tin []*Type // input parameter types\n-\tout []*Type // output parameter types\n+\n+type _imethod struct {\n+\tname *string\n+\tpkgPath *string\n+\ttyp *interface{}\n }\n
-// Method on interface type\n-type _imethod struct { // underscore is to avoid collision with C\n-\tname *string // name of method\n-\tpkgPath *string // nil for exported Names; otherwise import path\n-\ttyp *Type // .(*FuncType) underneath\n+\n+type interfaceType struct {\n+\tcommonType\n+\tmethods []_imethod\n }\n
-// InterfaceType represents an interface type.\n-type InterfaceType struct {\n+\n```
- **大幅な削除**: `Type`インターフェース、`kindBool`から`kindUnsafePointer`までの`kind`定数、`BoolType`から`StructType`までの具体的な型構造体(`ArrayType`, `SliceType`, `ChanType`, `FuncType`, `MapType`, `PtrType`, `StructType`など)がすべて削除されました。
- **コメントの変更**: ファイルの冒頭のコメントが「このファイルは、gdbが使用するDWARF情報に6lが変換できる型を提供するためにのみ存在する。他には何も使用しない。」と変更されました。これは、`runtime/type.go`がもはやGoの型情報の主要な定義元ではなく、デバッグ情報提供のための補助的な役割に限定されたことを明確に示しています。
- **残された型定義の簡素化**: 残された`commonType`、`_method`、`uncommonType`、`_imethod`、`interfaceType`の定義も、`reflect`パッケージの対応する型定義と一致するように簡素化され、`*Type`への参照が`*interface{}`に変更されています。
これらの変更は、Goの型システムが`reflect`パッケージを中心に再構築されたことを明確に示しており、`runtime`パッケージはより低レベルなランタイムの責務に特化するようになりました。
## 関連リンク
- **GitHubコミットページ**: [https://github.com/golang/go/commit/6a75ece01c99164d04752f26d58fdfec268d9139](https://github.com/golang/go/commit/6a75ece01c99164d04752f26d58fdfec268d9139)
- **Go Issue 2955**: このコミットが解決しようとした問題の一つ。具体的な内容は検索結果からは特定できませんでしたが、型システムとリフレクションの改善に関連するものです。
- **Go Issue 2968**: このコミットが解決しようとしたもう一つの問題。こちらも具体的な内容は特定できませんでしたが、型システムとリフレクションの改善に関連するものです。
## 参考にした情報源リンク
- Go reflect package internal structure:
- [https://scaler.com/topics/go-reflect-package/](https://scaler.com/topics/go-reflect-package/)
- [https://pieces.app/blog/go-reflection-tutorial/](https://pieces.app/blog/go-reflection-tutorial/)
- [https://coffeebytes.dev/posts/go-reflection-deep-dive/](https://coffeebytes.dev/posts/go-reflection-deep-dive/)
- [https://shichao.io/2013/09/02/go-reflection-deep-dive.html](https://shichao.io/2013/09/02/go-reflection-deep-dive.html)
- [https://medium.com/@mlowicki/go-reflection-deep-dive-2-reflect-type-and-reflect-value-100e22222222](https://medium.com/@mlowicki/go-reflection-deep-dive-2-reflect-type-and-reflect-value-100e22222222)
- [https://dev.to/ankit01/go-reflection-deep-dive-1-3k9](https://dev.to/ankit01/go-reflection-deep-dive-1-3k9)
- [https://go.dev/blog/laws-of-reflection](https://go.dev/blog/laws-of-reflection)
- [https://nutanix.dev/2023/08/29/go-reflection-deep-dive/](https://nutanix.dev/2023/08/29/go-reflection-deep-dive/)
- [https://josemukorivo.com/go-reflection-deep-dive/](https://josemukorivo.com/go-reflection-deep-dive/)
- [https://go.dev/doc/articles/laws_of_reflection.html](https://go.dev/doc/articles/laws_of_reflection.html)
- Go unsafe package Typeof Reflect Unreflect New NewArray removal:
- [https://go.dev/doc/go1#unsafe](https://go.dev/doc/go1#unsafe)
- Go issue 2955 & 2968:
- [https://go.dev/cl/5650069](https://go.dev/cl/5650069) (このコミットのChangeListページ)
- [https://youtrack.jetbrains.com/issue/GO-2968](https://youtrack.jetbrains.com/issue/GO-2968) (GoLand IDEのIssueトラッカーのGO-2968)
- [https://pkg.go.dev/vuln/GO-2024-2955](https://pkg.go.dev/vuln/GO-2024-2955) (Goの脆弱性レポートGO-2024-2955)
- [https://pkg.go.dev/vuln/GO-2024-2968](https://pkg.go.dev/vuln/GO-2024-2968) (Goの脆弱性レポートGO-2024-2968)
- [https://github.com/golang/vscode-go/issues/2955](https://github.com/golang/vscode-go/issues/2955) (VS Code Go拡張機能のIssue #2955)
- [https://github.com/grpc/grpc-go/issues/2955](https://github.com/grpc/grpc-go/issues/2955) (grpc-goのIssue #2955)
- [https://gochanges.org/go.golang.org/x/oauth2/commit/2955](https://gochanges.org/go.golang.org/x/oauth2/commit/2955) (golang.org/x/oauth2のコミット2955)