[インデックス 17051] ファイルの概要
このコミットは、Goランタイム内のfindnull
およびfindnullw
関数における型定義をint32
からintgo
に変更するものです。これは、Goの内部的な型表現の一貫性と移植性を向上させるための変更であり、特に異なるアーキテクチャ間での挙動の統一を目的としています。
コミット
commit 82f5ca1ef05970fc271dc7e1cacaed8e27f65910
Author: Rob Pike <r@golang.org>
Date: Tue Aug 6 21:49:03 2013 +1000
runtime: change int32 to intgo in findnull and findnullw
Update #6046.
This CL just does findnull and findnullw. There are other functions
to fix but doing them a few at a time will help isolate any (unlikely)
breakages these changes bring up in architectures I can't test
myself.
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/12520043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/82f5ca1ef05970fc271dc7e1cacaed8e27f65910
元コミット内容
このコミットの元の内容は、findnull
とfindnullw
というランタイム関数において、使用されているint32
型をintgo
型に変更するというものです。コミットメッセージには、この変更がIssue #6046に関連していること、そしてこの変更が他の関数にも適用される予定であるが、今回はfindnull
とfindnullw
に限定して行われたことが明記されています。これは、変更による潜在的な問題(特にテストが困難なアーキテクチャでの問題)を特定しやすくするための慎重なアプローチです。
変更の背景
Go言語は、異なるCPUアーキテクチャやオペレーティングシステム上で動作するように設計された、クロスプラットフォームな言語です。そのため、Goランタイムの内部実装では、特定のプラットフォームに依存しないように、データ型やメモリ管理を慎重に扱う必要があります。
このコミットの背景には、Goランタイム内部で使用される整数型の定義に関する課題がありました。特に、ポインタのサイズやアラインメントがアーキテクチャによって異なる場合、固定サイズのint32
のような型を使用すると、予期せぬ問題や非効率性が発生する可能性がありました。
intgo
型への変更は、このようなアーキテクチャ間の差異を吸収し、ランタイムコードの移植性と堅牢性を高めるための取り組みの一環です。Issue #6046は、おそらくこの型の一貫性の問題や、それによって引き起こされる可能性のあるバグやパフォーマンスの問題を追跡していたものと考えられます。
前提知識の解説
Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理する低レベルのコンポーネントです。これには、ガベージコレクション、スケジューリング、メモリ管理、プリミティブなI/O操作などが含まれます。Goプログラムは、コンパイル時にGoランタイムとリンクされ、実行時にランタイムの機能を利用します。ランタイムのコードは主にC言語とGo言語のサブセット(Goアセンブリ)で書かれており、プラットフォーム固有の最適化や低レベルの操作を可能にしています。
int32
型
int32
は、32ビット幅の符号付き整数型です。これは、多くのプログラミング言語で一般的な固定サイズの整数型であり、通常は-2,147,483,648から2,147,483,647までの値を表現できます。しかし、64ビットシステムでは、ポインタやサイズを表すために64ビットの整数が必要となる場合があります。
intgo
型
intgo
は、Goランタイム内部で使用される特殊な整数型です。これは、Goの組み込み型であるint
に対応するランタイム内部の型であり、そのサイズは実行されるアーキテクチャのポインタサイズに依存します。つまり、32ビットアーキテクチャでは32ビット、64ビットアーキテクチャでは64ビットの整数として扱われます。これにより、ポインタのオフセット計算やメモリサイズ指定など、アーキテクチャに依存する操作において、適切なサイズの整数型を使用できるようになります。intgo
は、Go言語のユーザーが直接使用する型ではなく、ランタイムの内部実装の詳細です。
findnull
とfindnullw
関数
これらの関数は、Goランタイム内部で文字列操作を行う際に使用されるユーティリティ関数であると推測されます。
findnull
: null終端されたバイト列(C言語スタイルの文字列)の長さを検索する関数。findnullw
: null終端されたワイド文字(UTF-16などの2バイト文字)列の長さを検索する関数。
これらの関数は、文字列の長さを計算するために、バイト列やワイド文字列を走査し、nullターミネータ(\0
または\0\0
)を見つけるまでカウントします。この「長さ」を格納する変数の型が、今回の変更の対象となっています。
技術的詳細
このコミットの核心は、Goランタイム内の特定の関数で、文字列の長さを表す変数の型をint32
からintgo
に変更することです。
Goランタイムは、C言語で書かれた部分が多く、C言語の型システムに影響を受けています。しかし、Go言語自体は、int
型がプラットフォームのワードサイズ(ポインタサイズ)に依存するという特性を持っています。例えば、32ビットシステムではint
は32ビットですが、64ビットシステムでは64ビットになります。
findnull
やfindnullw
のような関数は、メモリ上のバイト列やワイド文字列を走査し、その長さを返します。この「長さ」は、場合によっては非常に大きな値になる可能性があり、特に64ビットシステムでは32ビットの整数型では表現しきれない場合があります。また、ポインタ演算やメモリ割り当てのサイズ指定など、ランタイムの他の部分との連携を考えると、文字列の長さがポインタサイズと同じ幅を持つことが望ましい場合があります。
intgo
型を使用することで、以下の利点が得られます。
- 移植性の向上:
intgo
は、コンパイルされるアーキテクチャに応じて自動的に適切なサイズ(32ビットまたは64ビット)に調整されます。これにより、ランタイムコードが異なるアーキテクチャ間でより一貫して動作するようになります。 - 潜在的なバグの回避: 32ビットシステムでは問題なくても、64ビットシステムで文字列の長さが
int32
の最大値を超えた場合に発生する可能性のあるオーバーフローや、それに伴う誤ったメモリ操作などのバグを回避できます。 - パフォーマンスの最適化: アーキテクチャのネイティブなワードサイズに合わせた整数型を使用することで、CPUのレジスタを効率的に利用し、パフォーマンスが向上する可能性があります。
コミットメッセージにある「Update #6046」は、この型変更が特定のIssueの解決策であることを示唆しています。また、「This CL just does findnull and findnullw. There are other functions to fix but doing them a few at a time will help isolate any (unlikely) breakages these changes bring up in architectures I can't test myself.」という記述は、開発者がこの変更がもたらす可能性のある影響を慎重に評価していることを示しています。特に、すべてのアーキテクチャでテストできないため、段階的に変更を適用することで、問題が発生した場合に原因を特定しやすくする狙いがあります。
コアとなるコードの変更箇所
このコミットでは、主にsrc/pkg/runtime/
ディレクトリ以下の複数のC言語ソースファイルとヘッダファイルが変更されています。具体的な変更は、int32
型の変数をintgo
型に変更するものです。
以下に主要な変更箇所を抜粋し、その意味を解説します。
src/pkg/runtime/env_plan9.c
および src/pkg/runtime/env_posix.c
runtime·getenv
関数内で、環境変数の長さを格納するlen
変数の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/env_plan9.c
+++ b/src/pkg/runtime/env_plan9.c
@@ -8,7 +8,8 @@
byte*
runtime·getenv(int8 *s)
{
- int32 fd, len, n, r;
+ int32 fd, n, r;
+ intgo len;
byte file[128];
byte *p;
src/pkg/runtime/os_plan9.c
runtime·postnote
関数内で、メッセージの長さを格納するlen
変数の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -194,7 +194,8 @@ runtime·goexitsall(int8 *status)
int32
runtime·postnote(int32 pid, int8* msg)
{
- int32 fd, len;
+ int32 fd;
+ intgo len;
uint8 buf[128];
uint8 tmp[16];
uint8 *p, *q;
src/pkg/runtime/os_plan9_386.c
および src/pkg/runtime/os_plan9_amd64.c
runtime·sighandler
関数内で、シグナルハンドラの引数の長さを格納するlen
変数の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/os_plan9_386.c
+++ b/src/pkg/runtime/os_plan9_386.c
@@ -32,7 +32,7 @@ runtime·sighandler(void *v, int8 *s, G *gp)
Ureg *ureg;
uintptr *sp;
SigTab *sig, *nsig;
- int32 len, i;
+ intgo len, i;
src/pkg/runtime/print.c
gwrite
関数で、書き込むバイト数を表すn
引数の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -12,7 +12,7 @@ static void vprintf(int8*, byte*);
// write to goroutine-local buffer if diverting output,
// or else standard error.
static void
-gwrite(void *v, int32 n)
+gwrite(void *v, intgo n)
{
if(g == nil || g->writebuf == nil) {
runtime·write(2, v, n);
src/pkg/runtime/runtime.c
runtime·parsedebugvars
関数内で、デバッグ変数の長さを格納するn
変数の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -393,7 +393,7 @@ void
runtime·parsedebugvars(void)
{
byte *p;
- int32 i, n;
+ intgo i, n;
src/pkg/runtime/runtime.h
runtime·findnull
とruntime·findnullw
関数のプロトタイプ宣言において、戻り値の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -717,8 +717,8 @@ extern DebugVars runtime·debug;
*/
int32 runtime·strcmp(byte*, byte*);
byte* runtime·strstr(byte*, byte*);
-int32 runtime·findnull(byte*);
-int32 runtime·findnullw(uint16*);
+intgo runtime·findnull(byte*);
+intgo runtime·findnullw(uint16*);
void runtime·dump(byte*, int32);
int32 runtime·runetochar(byte*, int32);
int32 runtime·charntorune(int32*, uint8*, int32);
src/pkg/runtime/string.goc
runtime·findnull
とruntime·findnullw
関数の実装において、戻り値の型と内部で使用される長さ変数l
の型がint32
からintgo
に変更されています。
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -10,10 +10,10 @@ package runtime
String runtime·emptystring;
-int32
+intgo
runtime·findnull(byte *s)
{
- int32 l;
+ intgo l;
if(s == nil)
return 0;
@@ -22,10 +22,10 @@ runtime·findnull(byte *s)
return l;
}
-int32
+intgo
runtime·findnullw(uint16 *s)
{
- int32 l;
+ intgo l;
if(s == nil)
return 0;
コアとなるコードの解説
上記の変更は、GoランタイムのC言語部分において、文字列の長さやバイト数、その他のサイズ関連の値を扱う際に、固定サイズのint32
ではなく、アーキテクチャ依存のintgo
を使用するように統一するものです。
特にruntime/string.goc
におけるfindnull
とfindnullw
の変更は重要です。これらの関数は、C言語スタイルのnull終端文字列やワイド文字文字列の長さを計算します。返される長さがint32
の最大値を超える可能性がある場合、intgo
を使用することで、64ビットシステムでも正確な長さを表現できるようになります。
例えば、runtime·findnull(byte *s)
関数は、s
が指すバイト列の長さを計算します。もしこのバイト列が非常に長く、その長さが2^31 - 1
(約20億)を超える場合、int32
ではその長さを正確に表現できません。しかし、64ビットシステムでintgo
が64ビット幅を持つ場合、2^63 - 1
(約900京)までの長さを表現できるようになり、より大きな文字列を安全に扱えるようになります。
この変更は、Goランタイムの内部的な堅牢性と移植性を高めるための、細かではあるが重要な改善です。Go言語が様々なプラットフォームで安定して動作するための基盤を強化するものです。
関連リンク
- Go Issue #6046: https://github.com/golang/go/issues/6046 (このコミットが解決しようとしている問題の議論)
- Go CL 12520043: https://golang.org/cl/12520043 (このコミットに対応するGoのコードレビューシステムでの変更リスト)
参考にした情報源リンク
- Go言語のドキュメント (Goの型システム、特に
int
型の特性について): https://go.dev/doc/effective_go#int_types - Goランタイムのソースコード (Goランタイムの内部実装について): https://github.com/golang/go/tree/master/src/runtime
- C言語の整数型 (int32の一般的な特性について): (一般的なC言語の資料を参照)
- Plan 9 (Goランタイムの一部がPlan 9の設計思想に影響を受けているため): (Plan 9の資料を参照)
- POSIX (Goランタイムの一部がPOSIX標準に準拠しているため): (POSIX標準の資料を参照)
intgo
に関するGoのメーリングリストや設計ドキュメント (もし公開されていれば): (Goのメーリングリストアーカイブや設計ドキュメントを検索)- 検索結果から、
intgo
はGoの内部的な型であり、Goのソースコード内で定義されていることが確認できます。具体的な公開ドキュメントは少ないですが、Goのソースコード自体が最も正確な情報源となります。 intgo
は、Goのint
型がプラットフォームのワードサイズに依存するという特性を、C言語で書かれたランタイムコードで扱うための抽象化として機能します。- GoのIssue #6046の議論を直接参照することで、この変更の具体的な動機や背景をより深く理解できます。
- Goのコードレビューシステム (Gerrit) のCL (Change List) ページは、コミットの詳細な変更内容とレビューコメントを提供します。
- 検索結果から、