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

[インデックス 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パッケージにOffsetofSizeofという2つの関数を追加するものです。具体的には、unsafeimportという文字列定数の中にこれらの関数のシグネチャを記述しています。

コミットメッセージは簡潔に「update sysimport.c for unsafe.Offset and Sizeof」と述べており、R=kenはレビュー担当者がKen Thompsonであることを示唆しています。DELTA=2 (2 added, 0 deleted, 0 changed)は、2行が追加され、変更や削除はなかったことを示します。OCL=24643CL=24643は、Google内部の変更リスト(Changelist)番号であり、GoプロジェクトがGoogle内部で開発されていた時期の名残です。

変更の背景

Go言語のunsafeパッケージは、Goの型安全性をバイパスして低レベルのメモリ操作を可能にするためのものです。unsafe.Offsetofunsafe.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の標準ライブラリの一部であるunsafesyscallといった特殊なパッケージの「インポート定義」を提供することです。これらのパッケージは、通常のGoコードとは異なり、コンパイラが特別に扱う必要がある低レベルの機能を含んでいます。

具体的には、sysimport.cには、Goのソースコードとして解釈される文字列定数が含まれており、これらがコンパイラによって内部的に「インポート」されることで、Goプログラムがunsafeパッケージの関数や型を利用できるようになります。このファイルは、Goツールチェーンが新しいプラットフォームに移植される際や、syscallパッケージの生成時など、Goの内部動作において重要な役割を果たします。開発者が直接編集することは通常ありません。

OCLとCL

OCLCLは、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.Offsetofunsafe.Sizeofを呼び出した際に、コンパイラはこれらの関数が有効なものであると認識し、適切な内部処理(例えば、コンパイル時に定数として評価する、特定の組み込み命令に変換するなど)を行うことができます。

? any? intといったプレースホルダーは、Goの初期の内部表現における型パラメータの記述方法、あるいはコンパイラがこれらの関数の引数と戻り値の型を内部的に処理する方法を示唆している可能性があります。最終的なGo言語の仕様では、unsafe.Offsetoffunc Offsetof(any) uintptrunsafe.Sizeoffunc 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行が追加されています。

  1. "func unsafe.Offsetof (? any) (? int)\\n"
  2. "func unsafe.Sizeof (? any) (? int)\\n"

これらの行は、Goのunsafeパッケージ内でOffsetofSizeofという関数が定義されていることを、コンパイラに内部的に伝えるためのものです。\nは改行文字、\はエスケープシーケンスです。

コアとなるコードの解説

sysimport.c内のunsafeimport文字列は、Goコンパイラがunsafeパッケージの定義を「ハードコード」している部分です。これは、Goの標準ライブラリの一部であるunsafeパッケージが、通常のGoソースファイルとしてコンパイルされるのではなく、コンパイラ自身がその存在とシグネチャを認識している必要があるためです。

追加された2行は、それぞれunsafe.Offsetofunsafe.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.Offsetofunsafe.Sizeofを呼び出した際に、それらを有効な組み込み関数として認識し、コンパイル時に適切な処理(例えば、メモリサイズやオフセットの計算)を実行できるようになります。これにより、Go言語のユーザーは、unsafeパッケージを通じて低レベルのメモリ操作を行うことが可能になります。

関連リンク

参考にした情報源リンク