[インデックス 1643] ファイルの概要
このコミットは、Go言語のコンパイラ内部で使用されるsysimport.c
ファイルに、unsafe
パッケージのOffsetof
関数とSizeof
関数の定義を追加するものです。これにより、Goコンパイラがこれらの低レベル操作を認識し、適切に処理できるようになります。
コミット
commit 8f2b774ee15f1845253bc745c5fb6832b8501e68
Author: Rob Pike <r@golang.org>
Date: Sat Feb 7 14:48:32 2009 -0800
update sysimport.c for unsafe.Offset and Sizeof
R=ken
DELTA=2 (2 added, 0 deleted, 0 changed)
OCL=24643
CL=24643
---
src/cmd/gc/sysimport.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/cmd/gc/sysimport.c b/src/cmd/gc/sysimport.c
index da12b6361a..4d682d675d 100644
--- a/src/cmd/gc/sysimport.c
+++ b/src/cmd/gc/sysimport.c
@@ -65,5 +65,7 @@ char *sysimport =
char *unsafeimport =
"package unsafe\n"
"type unsafe.Pointer *any\n"
+"func unsafe.Offsetof (? any) (? int)\\n"\n
+"func unsafe.Sizeof (? any) (? int)\\n"\n
"\\n"\n
"$$\\n";
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8f2b774ee15f1845253bc745c5fb6832b8501e68
元コミット内容
このコミットは、Go言語のコンパイラの一部であるsrc/cmd/gc/sysimport.c
ファイルを更新し、unsafe
パッケージにOffsetof
とSizeof
という2つの関数を追加するものです。具体的には、unsafeimport
という文字列定数の中にこれらの関数のシグネチャを記述しています。
コミットメッセージは簡潔に「update sysimport.c for unsafe.Offset and Sizeof」と述べており、R=ken
はレビュー担当者がKen Thompsonであることを示唆しています。DELTA=2 (2 added, 0 deleted, 0 changed)
は、2行が追加され、変更や削除はなかったことを示します。OCL=24643
とCL=24643
は、Google内部の変更リスト(Changelist)番号であり、GoプロジェクトがGoogle内部で開発されていた時期の名残です。
変更の背景
Go言語のunsafe
パッケージは、Goの型安全性をバイパスして低レベルのメモリ操作を可能にするためのものです。unsafe.Offsetof
とunsafe.Sizeof
は、それぞれ構造体のフィールドのオフセットと、型のメモリサイズを取得するために使用されます。
このコミットが行われた2009年2月は、Go言語がまだ一般に公開される前の初期開発段階でした。Go言語の設計と実装が進む中で、特定の高度なユースケース(例えば、C言語との相互運用、非常に最適化されたデータ構造の実装、システムプログラミングなど)において、メモリの直接操作が必要となることが認識されました。
sysimport.c
はGoコンパイラの内部ファイルであり、特にcgo
(GoとC言語の連携ツール)や、Goツールチェーンのブートストラップ(自己コンパイル)プロセスにおいて、syscall
パッケージなどのシステム関連のパッケージを生成する際に利用されます。unsafe
パッケージの機能がGo言語のコア機能として導入されるにあたり、コンパイラがこれらの関数を正しく認識し、内部的に処理できるようにするために、sysimport.c
にその定義を組み込む必要がありました。
この変更は、unsafe
パッケージがGo言語の標準ライブラリの一部として確立され、その機能がコンパイラによってサポートされるための重要なステップでした。
前提知識の解説
Go言語のunsafe
パッケージ
unsafe
パッケージは、Go言語が提供する唯一の「安全でない」操作を許可するパッケージです。Goは通常、厳格な型安全性とメモリ安全性を保証しますが、unsafe
パッケージを使用することで、これらの保証を意図的にバイパスできます。これは、C言語のポインタ操作に似た低レベルのメモリ操作を可能にします。
unsafe.Pointer
: C言語のvoid*
に相当する汎用ポインタ型です。任意の型のポインタと相互に変換できます。これにより、異なる型のデータを同じメモリ領域として解釈したり、ポインタ演算を行ったりすることが可能になります。unsafe.Sizeof(v any) uintptr
: 引数v
のメモリ上でのサイズ(バイト単位)を返します。これは、変数の型がメモリ上でどれくらいの領域を占めるかを知るために使用されます。例えば、int
型が64ビットシステムで8バイトを占める場合、unsafe.Sizeof(someInt)
は8を返します。構造体の場合、パディング(アライメントのために挿入される未使用バイト)も考慮されたサイズが返されます。unsafe.Offsetof(v.field any) uintptr
: 構造体v
の特定のフィールドfield
が、構造体の先頭から何バイト目に位置するか(オフセット)を返します。これは、構造体内の特定のフィールドに直接ポインタでアクセスする際に利用されます。
unsafe
パッケージは非常に強力ですが、その名の通り「安全でない」ため、誤用するとメモリ破壊、クラッシュ、移植性のないコード、デバッグが困難なバグなどを引き起こす可能性があります。そのため、Goの標準的なプログラミングではほとんど使用されず、特定のパフォーマンス最適化やシステムレベルのプログラミング、C言語との連携など、限定された状況でのみ慎重に利用されます。
Goコンパイラのsysimport.c
sysimport.c
は、Goコンパイラの内部ツールチェーンの一部であるC言語のソースファイルです。GoコンパイラはGo言語で書かれていますが、そのブートストラッププロセスや、C言語との連携(cgo
)のために、一部C言語のコードも使用しています。
sysimport.c
の主な役割は、Goの標準ライブラリの一部であるunsafe
やsyscall
といった特殊なパッケージの「インポート定義」を提供することです。これらのパッケージは、通常のGoコードとは異なり、コンパイラが特別に扱う必要がある低レベルの機能を含んでいます。
具体的には、sysimport.c
には、Goのソースコードとして解釈される文字列定数が含まれており、これらがコンパイラによって内部的に「インポート」されることで、Goプログラムがunsafe
パッケージの関数や型を利用できるようになります。このファイルは、Goツールチェーンが新しいプラットフォームに移植される際や、syscall
パッケージの生成時など、Goの内部動作において重要な役割を果たします。開発者が直接編集することは通常ありません。
OCLとCL
OCL
とCL
は、Google内部で使われていた変更管理システムの用語です。
- CL (Changelist): Googleのバージョン管理システムにおける、コード変更の単位を指します。これは、GitのコミットやPerforceのチェンジリストに相当します。開発者がコードを変更し、レビューのために提出する際にCLが作成されます。
- OCL: おそらく「Our Changelist」の略で、Google内部の特定のシステムや文脈におけるCLを指すものと考えられます。Go言語は元々Google内部で開発が始まったため、初期のコミットメッセージにはこのような内部的な参照が含まれています。
これらの番号は、Goプロジェクトがオープンソース化される前の、Google内部での開発履歴を追跡するための識別子として機能していました。
技術的詳細
このコミットの技術的詳細は、Goコンパイラの内部動作、特にunsafe
パッケージの取り扱いと、Go言語のブートストラッププロセスに関連しています。
Goコンパイラは、Goのソースコードを解析し、機械語に変換する過程で、Go言語の組み込み関数や特殊なパッケージ(unsafe
など)を特別に扱います。通常のGoパッケージは、Goのソースファイルとして存在し、コンパイラによって解析されますが、unsafe
パッケージのような低レベルの機能を提供するものは、コンパイラ自身がその存在とシグネチャを「知っている」必要があります。
sysimport.c
ファイル内のunsafeimport
というC言語の文字列定数は、Goコンパイラが内部的に使用するGoコードのスニペットです。このスニペットは、unsafe
パッケージの型(unsafe.Pointer
)と関数(unsafe.Offsetof
, unsafe.Sizeof
)の宣言を含んでいます。
char *unsafeimport =
"package unsafe\n"
"type unsafe.Pointer *any\n"
"func unsafe.Offsetof (? any) (? int)\\n"\n
"func unsafe.Sizeof (? any) (? int)\\n"\n
"\\n"\n
"$$\\n";
この文字列は、Goコンパイラが起動する際に読み込まれ、あたかもGoのソースファイルが存在するかのようにunsafe
パッケージの定義がコンパイラのシンボルテーブルに登録されます。これにより、Goのプログラムがimport "unsafe"
と記述し、unsafe.Offsetof
やunsafe.Sizeof
を呼び出した際に、コンパイラはこれらの関数が有効なものであると認識し、適切な内部処理(例えば、コンパイル時に定数として評価する、特定の組み込み命令に変換するなど)を行うことができます。
? any
や? int
といったプレースホルダーは、Goの初期の内部表現における型パラメータの記述方法、あるいはコンパイラがこれらの関数の引数と戻り値の型を内部的に処理する方法を示唆している可能性があります。最終的なGo言語の仕様では、unsafe.Offsetof
はfunc Offsetof(any) uintptr
、unsafe.Sizeof
はfunc Sizeof(any) uintptr
というシグネチャになります。このコミット時点では、まだその最終的な形が固まっていなかったか、あるいはコンパイラ内部での表現が異なっていた可能性があります。
この変更は、Go言語のunsafe
パッケージが言語仕様の一部として安定し、コンパイラがその機能を完全にサポートするための基盤を築いたことを意味します。
コアとなるコードの変更箇所
変更はsrc/cmd/gc/sysimport.c
ファイルに集中しています。
--- a/src/cmd/gc/sysimport.c
+++ b/src/cmd/gc/sysimport.c
@@ -65,5 +65,7 @@ char *sysimport =
char *unsafeimport =
"package unsafe\\n"\n
"type unsafe.Pointer *any\\n"\n
+"func unsafe.Offsetof (? any) (? int)\\n"\n
+"func unsafe.Sizeof (? any) (? int)\\n"\n
"\\n"\n
"$$\\n";
具体的には、unsafeimport
というC言語の文字列定数に、以下の2行が追加されています。
"func unsafe.Offsetof (? any) (? int)\\n"
"func unsafe.Sizeof (? any) (? int)\\n"
これらの行は、Goのunsafe
パッケージ内でOffsetof
とSizeof
という関数が定義されていることを、コンパイラに内部的に伝えるためのものです。\n
は改行文字、\
はエスケープシーケンスです。
コアとなるコードの解説
sysimport.c
内のunsafeimport
文字列は、Goコンパイラがunsafe
パッケージの定義を「ハードコード」している部分です。これは、Goの標準ライブラリの一部であるunsafe
パッケージが、通常のGoソースファイルとしてコンパイルされるのではなく、コンパイラ自身がその存在とシグネチャを認識している必要があるためです。
追加された2行は、それぞれunsafe.Offsetof
とunsafe.Sizeof
という関数のシグネチャを定義しています。
func unsafe.Offsetof (? any) (? int)
: これは、unsafe
パッケージにOffsetof
という関数があり、任意の型(? any
)を引数に取り、整数型(? int
)を返すことを示しています。Go言語の最終的な仕様では、戻り値はuintptr
型(ポインタのサイズを表す符号なし整数型)になりますが、このコミット時点では内部的にint
として扱われていたか、あるいはより汎用的なプレースホルダーとしてint
が使われていた可能性があります。func unsafe.Sizeof (? any) (? int)
: 同様に、unsafe
パッケージにSizeof
という関数があり、任意の型(? any
)を引数に取り、整数型(? int
)を返すことを示しています。こちらも最終的な仕様ではuintptr
を返します。
これらの定義がunsafeimport
文字列に追加されることで、Goコンパイラは、Goプログラムがunsafe.Offsetof
やunsafe.Sizeof
を呼び出した際に、それらを有効な組み込み関数として認識し、コンパイル時に適切な処理(例えば、メモリサイズやオフセットの計算)を実行できるようになります。これにより、Go言語のユーザーは、unsafe
パッケージを通じて低レベルのメモリ操作を行うことが可能になります。
関連リンク
- Go言語の
unsafe
パッケージのドキュメント: https://pkg.go.dev/unsafe - Go言語のソースコードリポジトリ: https://github.com/golang/go
参考にした情報源リンク
- Go言語の
unsafe
パッケージに関する解説記事 (例: Go 101, HackerNoonなど): - Goコンパイラの内部構造に関する情報 (例:
sysimport.c
の役割に関する議論):- https://go.dev/src/cmd/cgo/doc.go (cgoのドキュメント内で
sysimport.c
への言及がある場合)
- https://go.dev/src/cmd/cgo/doc.go (cgoのドキュメント内で
- GoogleのChangelist (CL) に関する情報:
- https://graphite.dev/blog/what-is-a-changelist
- https://abseil.io/resources/swe-book/html/ch12.html (Googleのソフトウェアエンジニアリングに関する書籍)
- Go言語の初期開発に関する歴史的資料 (もしあれば):
- Go言語の公式ブログや初期の設計ドキュメントなど。