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

[インデックス 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

元コミット内容

このコミットの元の内容は、findnullfindnullwというランタイム関数において、使用されているint32型をintgo型に変更するというものです。コミットメッセージには、この変更がIssue #6046に関連していること、そしてこの変更が他の関数にも適用される予定であるが、今回はfindnullfindnullwに限定して行われたことが明記されています。これは、変更による潜在的な問題(特にテストが困難なアーキテクチャでの問題)を特定しやすくするための慎重なアプローチです。

変更の背景

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言語のユーザーが直接使用する型ではなく、ランタイムの内部実装の詳細です。

findnullfindnullw関数

これらの関数は、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ビットになります。

findnullfindnullwのような関数は、メモリ上のバイト列やワイド文字列を走査し、その長さを返します。この「長さ」は、場合によっては非常に大きな値になる可能性があり、特に64ビットシステムでは32ビットの整数型では表現しきれない場合があります。また、ポインタ演算やメモリ割り当てのサイズ指定など、ランタイムの他の部分との連携を考えると、文字列の長さがポインタサイズと同じ幅を持つことが望ましい場合があります。

intgo型を使用することで、以下の利点が得られます。

  1. 移植性の向上: intgoは、コンパイルされるアーキテクチャに応じて自動的に適切なサイズ(32ビットまたは64ビット)に調整されます。これにより、ランタイムコードが異なるアーキテクチャ間でより一貫して動作するようになります。
  2. 潜在的なバグの回避: 32ビットシステムでは問題なくても、64ビットシステムで文字列の長さがint32の最大値を超えた場合に発生する可能性のあるオーバーフローや、それに伴う誤ったメモリ操作などのバグを回避できます。
  3. パフォーマンスの最適化: アーキテクチャのネイティブなワードサイズに合わせた整数型を使用することで、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·findnullruntime·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·findnullruntime·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におけるfindnullfindnullwの変更は重要です。これらの関数は、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言語のドキュメント (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) ページは、コミットの詳細な変更内容とレビューコメントを提供します。