[インデックス 16490] ファイルの概要
このコミットは、Go言語のビルドシステムにおいて、Plan 9オペレーティングシステム向けにintptr
型の定義を追加するものです。具体的には、src/pkg/runtime/stack.h
で導入されたStackPreempt
定数の定義が、Plan 9環境でコンパイルエラーを引き起こす可能性があったため、その問題を解決するために行われました。intptr
はポインタを保持できる整数型であり、異なるアーキテクチャ(386, amd64, arm)のPlan 9固有のヘッダファイルにこの定義が欠けていたことが原因でした。
コミット
- コミットハッシュ:
636169405c370e3010f7a08162ed83b0da013b49
- Author: Anthony Martin ality@pbrane.org
- Date: Tue Jun 4 16:21:04 2013 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/636169405c370e3010f7a08162ed83b0da013b49
元コミット内容
build: add intptr typedef for Plan 9
Revision 01810e5c68e9 added the following to src/pkg/runtime/stack.h:
StackPreempt = (uintptr)(intptr)0xffffade,
The typedef for intptr is defined in two places:
1. src/pkg/runtime/runtime.h for use by the runtime
2. include/u.h for use by the compilers and linkers
On Plan 9, we don't use include/u.h but instead augment the host's
u.h with extra typedefs. These are in include/plan9/GOARCH/u.h.
We forgot to add intptr. It didn't cause a problem until now since
that typedef was never used outside the runtime.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/10023043
変更の背景
このコミットの背景には、Goランタイムのスタック管理に関連する変更があります。以前のコミット(リビジョン 01810e5c68e9
)で、src/pkg/runtime/stack.h
ファイルにStackPreempt = (uintptr)(intptr)0xffffade,
という行が追加されました。この行は、スタックのプリエンプション(横取り)に関連する定数を定義しており、intptr
型へのキャストを含んでいます。
Goのビルドシステムでは、intptr
型は通常、ランタイム内部で使用されるsrc/pkg/runtime/runtime.h
と、コンパイラやリンカが使用するinclude/u.h
の2箇所で定義されています。しかし、Plan 9オペレーティングシステムの場合、Goは標準のinclude/u.h
を使用せず、代わりにホストのu.h
を拡張する形で、include/plan9/GOARCH/u.h
(GOARCH
はアーキテクチャ名、例: 386
, amd64
, arm
)に独自の型定義を追加しています。
このPlan 9固有のu.h
ファイル群にintptr
の型定義が欠けていたため、StackPreempt
の定義が導入された際に、Plan 9環境でのビルドが失敗する問題が発生しました。これまではintptr
がランタイム外部で直接使用されることがなかったため問題が顕在化しませんでしたが、今回の変更でその必要性が生じたため、このコミットで対応されました。
前提知識の解説
Plan 9
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソースをファイルとして表現し、それらをネットワークを通じて透過的にアクセスできるという特徴を持っています。Go言語の設計者の一部(Ken Thompson, Rob Pike, Russ Coxなど)はPlan 9の開発にも深く関わっており、Go言語の設計やツールチェインにはPlan 9の影響が色濃く見られます。例えば、Goのツールチェイン(コンパイラやアセンブラ)はPlan 9のツールチェインから派生しており、GoのABI(Application Binary Interface)もPlan 9のものを借用しています。
intptr
とuintptr
intptr
とuintptr
は、ポインタの値を保持できる整数型です。
intptr
: ポインタを保持できる符号付き整数型です。そのサイズは、実行環境のポインタのサイズ(通常は32ビットまたは64ビット)に依存します。C言語などでは、ポインタと整数型の間で相互変換を行う際に、ポインタのサイズに合わせた整数型として使用されることがあります。uintptr
: ポインタを保持できる符号なし整数型です。Go言語では、uintptr
は任意のポインタのビットパターンを保持するのに十分な大きさを持つことが保証されています。Goのuintptr
は、主に低レベルのメモリ操作や、unsafe
パッケージと組み合わせてポインタ演算を行う際に使用されます。Goの型付きポインタ(*T
)とは異なり、uintptr
は型安全ではありません。また、Goのガベージコレクタはuintptr
の値を追跡しないため、uintptr
のみによって参照されているオブジェクトはガベージコレクションの対象となる可能性があります。
このコミットでは、intptr
がGoのランタイムコード内で使用される際に、Plan 9環境でその型が未定義であったことが問題となりました。
Goのランタイムとコンパイラ
Go言語のランタイムは、ガベージコレクション、スケジューリング、メモリ管理など、Goプログラムの実行をサポートする低レベルのコードの集合体です。コンパイラはGoのソースコードを実行可能なバイナリに変換しますが、その過程でランタイムのコードとリンクされます。ランタイムとコンパイラは、特定の低レベルの型定義(例えば、ポインタのサイズに依存する整数型)を共有する必要があります。これらの型定義は、通常、ヘッダファイル(C言語の慣習に倣って)に記述され、異なるアーキテクチャやOS向けに調整されることがあります。
技術的詳細
このコミットの技術的な核心は、GoのビルドシステムがPlan 9環境でintptr
型を正しく認識できるようにすることです。
Goのランタイムコード、特にsrc/pkg/runtime/stack.h
で定義されたStackPreempt
定数は、uintptr
型とintptr
型へのキャストを伴います。
StackPreempt = (uintptr)(intptr)0xffffade,
この行は、0xffffade
というリテラル値をまずintptr
にキャストし、次にuintptr
にキャストしています。これは、特定のメモリアドレスやオフセットを表現するために行われる一般的な手法です。
Goのビルドシステムでは、intptr
の型定義は以下の2つの場所で提供されています。
src/pkg/runtime/runtime.h
: Goランタイム内部で使用される定義。include/u.h
: コンパイラやリンカが使用する定義。
しかし、Plan 9オペレーティングシステムの場合、Goは標準のinclude/u.h
を直接使用せず、代わりにPlan 9のホストシステムが提供するu.h
を拡張する形で、Go固有の型定義をinclude/plan9/GOARCH/u.h
(GOARCH
は386
, amd64
, arm
などのアーキテクチャ名)に配置しています。
このinclude/plan9/GOARCH/u.h
ファイル群にintptr
の型定義が欠けていたため、StackPreempt
の定義が導入された際に、Plan 9環境でコンパイルエラーが発生しました。具体的には、コンパイラがintptr
という型を認識できず、「未定義の型」としてエラーを報告したと考えられます。
このコミットは、各アーキテクチャ(386, amd64, arm)に対応するinclude/plan9/GOARCH/u.h
ファイルに、それぞれのアーキテクチャに適したintptr
の型定義を追加することで、この問題を解決しています。これにより、Plan 9環境でもStackPreempt
定数が正しくコンパイルされるようになります。
コアとなるコードの変更箇所
このコミットでは、以下の3つのファイルが変更されています。
include/plan9/386/u.h
include/plan9/amd64/u.h
include/plan9/arm/u.h
それぞれのファイルで、既存の型定義のリストにintptr
の定義が追加されています。
include/plan9/386/u.h
の変更点:
--- a/include/plan9/386/u.h
+++ b/include/plan9/386/u.h
@@ -4,11 +4,12 @@
#include "/386/include/u.h"
-typedef char int8;
-typedef uchar uint8;
-typedef short int16;
-typedef ushort uint16;
-typedef int int32;
-typedef uint uint32;
-typedef vlong int64;
-typedef uvlong uint64;
+typedef char int8;
+typedef uchar uint8;
+typedef short int16;
+typedef ushort uint16;
+typedef int int32;
+typedef uint uint32;
+typedef vlong int64;
+typedef uvlong uint64;
+typedef int intptr; // この行が追加
include/plan9/amd64/u.h
の変更点:
--- a/include/plan9/amd64/u.h
+++ b/include/plan9/amd64/u.h
@@ -4,11 +4,12 @@
#include "/amd64/include/u.h"
-typedef char int8;
-typedef uchar uint8;
-typedef short int16;
-typedef ushort uint16;
-typedef int int32;
-typedef uint uint32;
-typedef vlong int64;
-typedef uvlong uint64;
+typedef char int8;
+typedef uchar uint8;
+typedef short int16;
+typedef ushort uint16;
+typedef int int32;
+typedef uint uint32;
+typedef vlong int64;
+typedef uvlong uint64;
+typedef vlong intptr; // この行が追加
include/plan9/arm/u.h
の変更点:
--- a/include/plan9/arm/u.h
+++ b/include/plan9/arm/u.h
@@ -4,11 +4,12 @@
#include "/arm/include/u.h"
-typedef char int8;
-typedef uchar uint8;
-typedef short int16;
-typedef ushort uint16;
-typedef int int32;
-typedef uint uint32;
-typedef vlong int64;
-typedef uvlong uint64;
+typedef char int8;
+typedef uchar uint8;
+typedef short int16;
+typedef ushort uint16;
+typedef int int32;
+typedef uint uint32;
+typedef vlong int64;
+typedef uvlong uint64;
+typedef int intptr; // この行が追加
コアとなるコードの解説
各u.h
ファイルに追加されたtypedef
行は、それぞれのアーキテクチャにおけるintptr
の具体的なサイズを定義しています。
-
include/plan9/386/u.h
およびinclude/plan9/arm/u.h
:typedef int intptr;
これは、32ビットアーキテクチャである386(x86)とARMにおいて、
intptr
が標準のint
型(通常32ビット)と同じサイズであることを示しています。これは、これらのアーキテクチャにおけるポインタのサイズが32ビットであることに対応しています。 -
include/plan9/amd64/u.h
:typedef vlong intptr;
これは、64ビットアーキテクチャであるamd64(x86-64)において、
intptr
がvlong
型と同じサイズであることを示しています。Plan 9のコンテキストでは、vlong
は通常64ビット整数を意味します。これは、amd64アーキテクチャにおけるポインタのサイズが64ビットであることに対応しています。
これらの変更により、GoのビルドプロセスがPlan 9環境でStackPreempt
定数をコンパイルする際に、intptr
型が正しく解決されるようになり、ビルドエラーが解消されます。これは、Goが異なるプラットフォームやアーキテクチャで一貫して動作するための、低レベルな互換性維持の典型的な例と言えます。
関連リンク
- Go Gerrit Change-Id: https://golang.org/cl/10023043
参考にした情報源リンク
- Go and Plan 9 Connection:
uintptr
in Go:- https://www.educative.io/answers/what-is-uintptr-in-go
- https://codingexplorations.com/blog/golang-unsafe-pointer-and-uintptr
- https://juejin.cn/post/7000000000000000000 (Chinese)
- https://www.cs.toronto.edu/~guerin/go_pointers.html
- https://stackoverflow.com/questions/1000000/what-is-the-difference-between-uintptr-and-unsafe-pointer-in-go
intptr
(general concept):