[インデックス 18552] ファイルの概要
このコミットは、Go言語のランタイムおよびコンパイラ (cmd/gc
) に関連する変更を取り消すものです。具体的には、以前に導入された precisestack
機能のデフォルト有効化を取り消し、その結果として発生した32ビットビルドの破損を修正することを目的としています。
コミット
commit aad23e708c55f063a64eaa055e8d9d6c2294c9f4
Author: Russ Cox <rsc@golang.org>
Date: Mon Feb 17 21:34:58 2014 -0500
undo CL 64100044 / 04d062c2e81c
broke 32-bit builds
««« original CL description
cmd/gc, runtime: enable precisestack by default
Precisestack makes stack collection completely precise,
in the sense that there are no "used and not set" errors
in the collection of stack frames, no times where the collector
reads a pointer from a stack word that has not actually been
initialized with a pointer (possibly a nil pointer) in that function.
The most important part is interfaces: precisestack means
that if reading an interface value, the interface value is guaranteed
to be initialized, meaning that the type word can be relied
upon to be either nil or a valid interface type word describing
the data word.
This requires additional zeroing of certain values on the stack
on entry, which right now costs about 5% overall execution
time in all.bash. That cost will come down before Go 1.3
(issue 7345).
There are at least two known garbage collector bugs right now,
issues 7343 and 7344. The first happens even without precisestack.
The second I have only seen with precisestack, but that does not
mean that precisestack is what causes it. In fact it is very difficult
to explain by what precisestack does directly. Precisestack may
be exacerbating an existing problem. Both of those issues are
marked for Go 1.3 as well.
The reasons for enabling precisestack now are to give it more
time to soak and because the copying stack work depends on it.
LGTM=r
R=r
CC=golang-codereviews, iant, khr
https://golang.org/cl/64100044
»»»
TBR=r
CC=golang-codereviews
https://golang.org/cl/65230043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aad23e708c55f063a64eaa055e8d9d6c2294c9f4
元コミット内容
このコミットは、CL 64100044
(ハッシュ 04d062c2e81c
) で行われた変更を取り消すものです。元のコミットの目的は、Goランタイムにおいて「precisestack」機能をデフォルトで有効にすることでした。
元のコミットメッセージによると、precisestack
はスタックのガベージコレクションを完全に正確にするための機能です。これにより、スタックフレームの収集時に「使用されているが設定されていない」エラー("used and not set"
errors)が発生せず、ガベージコレクタがポインタを読み取る際に、そのスタックワードが実際にポインタ(nilポインタを含む)で初期化されていないという状況がなくなります。
特に重要なのはインターフェースの扱いでした。precisestack
が有効な場合、インターフェース値が初期化されていることが保証され、その型ワードがnilであるか、データワードを記述する有効なインターフェース型ワードであるかのいずれかとして信頼できるようになります。
この機能の有効化には、関数エントリ時にスタック上の一部の値を追加でゼロクリアする必要があり、その時点ではall.bash
テストスイート全体の実行時間に約5%のオーバーヘッドが発生していました。このコストはGo 1.3のリリースまでに削減される予定でした(issue 7345)。
また、precisestack
の有効化時には、少なくとも2つの既知のガベージコレクタのバグ(issue 7343と7344)が存在していました。issue 7343はprecisestack
がなくても発生するものでしたが、issue 7344はprecisestack
が有効な場合にのみ確認されており、precisestack
が既存の問題を悪化させている可能性が指摘されていました。これらの問題もGo 1.3で修正される予定でした。
precisestack
をデフォルトで有効にする理由は、より多くのテスト期間(soak time)を確保するためと、コピー型スタック(copying stack)の実装がこの機能に依存していたためと説明されています。
変更の背景
元のコミット(CL 64100044
)でprecisestack
をデフォルトで有効にした後、32ビットビルドが破損するという問題が発生しました。このコミット(CL 65230043
)は、その問題を解決するために、precisestack
のデフォルト有効化を取り消すことを目的としています。これは、新機能の導入が予期せぬ副作用(特に特定のアーキテクチャでのビルド失敗)を引き起こした場合に、安定性を優先して一時的に変更をロールバックするという、ソフトウェア開発における一般的なプラクティスです。
Go 1.3のリリースに向けて、ガベージコレクタの改善とスタック管理の精密化は重要な目標でしたが、その過程で発生した互換性の問題に対処する必要がありました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の内部動作に関する知識が役立ちます。
- Goのガベージコレクション (GC): Goはトレース型ガベージコレクタを使用しており、プログラムが使用しているメモリ(到達可能なオブジェクト)を特定し、それ以外のメモリを解放します。GCはスタック、ヒープ、グローバル変数などをスキャンしてポインタを識別し、到達可能性を判断します。
- スタックとポインタ: Goの関数呼び出しでは、ローカル変数や引数がスタック上に配置されます。これらの変数の中には、ヒープ上のオブジェクトを指すポインタが含まれることがあります。GCが正確に動作するためには、スタック上のどのワードがポインタであり、どのワードがポインタではないかを正確に識別する必要があります。
- 「Used and not set」エラー: これは、ガベージコレクタがスタック上のメモリ領域をスキャンする際に、まだ有効な値が設定されていない(初期化されていない)にもかかわらず、ポインタとして解釈しようとすることで発生する可能性のある問題です。これにより、GCが不正なメモリをたどったり、クラッシュしたりする可能性があります。
- インターフェース (Interface): Goのインターフェースは、型と値のペアとして内部的に表現されます。型はインターフェースが保持する具体的な型の情報、値はその具体的な型のインスタンスへのポインタです。GCがインターフェース値を正確に処理するためには、この型と値のペアが常に有効な状態であることが重要です。特に、型ワードがnilであるか、有効な型情報を含んでいる必要があります。
GOEXPERIMENT
環境変数: Goのビルドシステムでは、GOEXPERIMENT
環境変数を使用して、実験的な機能や開発中の機能を有効/無効にすることができます。これにより、新しい機能をデフォルトで有効にする前に、特定の環境でテストを行うことが可能になります。- Goのビルドプロセス (
cmd/gc
):cmd/gc
はGoのコンパイラであり、Goのソースコードを機械語に変換します。このプロセスには、スタックフレームのレイアウトやガベージコレクションに関するメタデータの生成も含まれます。 - Goのランタイム (
src/pkg/runtime
): Goのランタイムは、ガベージコレクタ、スケジューラ、メモリ管理など、Goプログラムの実行をサポートする低レベルのコードを含んでいます。
技術的詳細
このコミットは、precisestack
機能のデフォルト有効化を取り消すことで、32ビットビルドの破損を修正します。
precisestack
は、スタック上のポインタの識別精度を高めるための機能です。従来のGoのGCでは、スタック上のポインタを識別する際に、一部のヒューリスティックや保守的なアプローチが用いられることがありました。これは、パフォーマンス上の理由や、コンパイラがスタック上のすべてのメモリワードの正確な状態を常に追跡するのが困難であるためです。しかし、このアプローチは「used and not set」エラーのような問題を引き起こす可能性がありました。
precisestack
が目指したのは、関数エントリ時にスタック上の特定の領域をゼロクリアするなどして、スタック上のすべてのポインタ候補が常に既知の状態(有効なポインタかnilポインタ)であることを保証することです。これにより、GCはスタックをスキャンする際に、どのワードがポインタであるかを確実に識別できるようになり、ガベージコレクションの正確性と信頼性が向上します。特にインターフェース値の正確な処理は、Goの型システムとGCの健全性にとって非常に重要です。
しかし、この「追加のゼロクリア」やスタックフレームの管理方法の変更が、32ビットアーキテクチャの特定のコンパイルパスやランタイムの挙動と衝突し、ビルドが失敗する原因となったと考えられます。32ビットシステムでは、ポインタのサイズやアラインメント、レジスタの使用方法などが64ビットシステムとは異なるため、低レベルの最適化やメモリ管理の変更が予期せぬ問題を引き起こすことがあります。
このコミットでは、precisestack
をデフォルトで有効にする設定を元に戻し、GOEXPERIMENT
環境変数を通じて明示的に有効にした場合にのみ機能するように変更しています。これにより、32ビットビルドの破損を回避しつつ、開発者がprecisestack
のテストを継続できるようにしています。
コアとなるコードの変更箇所
このコミットによる変更は、以下の2つのファイルにわたります。
-
src/cmd/gc/lex.c
:setexp
関数内で、precisestack_enabled = 1; // on by default
という行が削除されました。- この変更により、コンパイラ側で
precisestack
がデフォルトで有効になる設定が取り消されます。
-
src/pkg/runtime/proc.c
:runtime·schedinit
関数内で、runtime·precisestack = true; // haveexperiment("precisestack");
という行が、runtime·precisestack = haveexperiment("precisestack");
に変更されました。- この変更により、ランタイム側で
precisestack
の有効/無効が、ハードコードされたtrue
ではなく、haveexperiment("precisestack")
関数の結果(つまりGOEXPERIMENT
環境変数の設定)に依存するようになります。
コアとなるコードの解説
src/cmd/gc/lex.c
の変更
src/cmd/gc/lex.c
はGoコンパイラの字句解析器(lexer)の一部であり、コンパイル時の実験的フラグ(GOEXPERIMENT
)の処理も行います。
setexp
関数は、GOEXPERIMENT
環境変数の値を解析し、対応する実験的機能を有効にする役割を担っています。
元のコードでは、precisestack_enabled = 1; // on by default
という行が明示的に存在し、GOEXPERIMENT
の設定に関わらずprecisestack
をデフォルトで有効にしていました。これは、precisestack
をGo 1.3のデフォルト機能として導入するためのステップでした。
このコミットでは、この行を削除することで、precisestack
のデフォルト有効化を取り消しています。これにより、precisestack
はGOEXPERIMENT
にprecisestack
が指定された場合にのみ有効になるように戻されます。
src/pkg/runtime/proc.c
の変更
src/pkg/runtime/proc.c
はGoランタイムのプロセッサ(P)とスケジューラ(M)の初期化に関連するコードを含んでいます。
runtime·schedinit
関数は、ランタイムの初期化処理の早い段階で呼び出されます。
元のコードでは、runtime·precisestack = true;
と直接true
が代入されており、ランタイムレベルでもprecisestack
が常に有効になるように設定されていました。コメントアウトされた// haveexperiment("precisestack");
は、この行が以前はGOEXPERIMENT
に依存していたが、デフォルト有効化のために変更されたことを示唆しています。
このコミットでは、この行をruntime·precisestack = haveexperiment("precisestack");
に戻しています。haveexperiment
関数は、GOEXPERIMENT
環境変数に特定の文字列(この場合は"precisestack"
)が含まれているかどうかをチェックします。この変更により、ランタイムのprecisestack
フラグは、コンパイラと同様に、GOEXPERIMENT
の設定に依存するようになります。
これらの変更は、precisestack
をデフォルトで有効にするという方針を一時的に撤回し、32ビットビルドの安定性を優先するためのものです。これにより、開発者は引き続きGOEXPERIMENT=precisestack
を設定することでこの機能をテストできますが、デフォルトのビルドでは無効になります。
関連リンク
- 元のコミット (CL 64100044): https://golang.org/cl/64100044
- このコミット (CL 65230043): https://golang.org/cl/65230043
- Go Issue 7345 (precisestackのコスト削減): https://golang.org/issue/7345
- Go Issue 7343 (GCバグ): https://golang.org/issue/7343
- Go Issue 7344 (GCバグ): https://golang.org/issue/7344
参考にした情報源リンク
- Go言語の公式ドキュメントおよびソースコード
- GoのIssueトラッカー
- Goのコードレビューシステム (Gerrit)
- Goのガベージコレクションに関する一般的な情報源 (例: "Go's Garbage Collector: From 1.3 to 1.5" by Rick Hudson, "The Go Programming Language" by Alan A. A. Donovan and Brian W. Kernighan)
- 32ビットアーキテクチャと64ビットアーキテクチャにおけるコンパイラとランタイムの挙動の違いに関する一般的な知識# [インデックス 18552] ファイルの概要
このコミットは、Go言語のランタイムおよびコンパイラ (cmd/gc
) に関連する変更を取り消すものです。具体的には、以前に導入された precisestack
機能のデフォルト有効化を取り消し、その結果として発生した32ビットビルドの破損を修正することを目的としています。
コミット
commit aad23e708c55f063a64eaa055e8d9d6c2294c9f4
Author: Russ Cox <rsc@golang.org>
Date: Mon Feb 17 21:34:58 2014 -0500
undo CL 64100044 / 04d062c2e81c
broke 32-bit builds
««« original CL description
cmd/gc, runtime: enable precisestack by default
Precisestack makes stack collection completely precise,
in the sense that there are no "used and not set" errors
in the collection of stack frames, no times where the collector
reads a pointer from a stack word that has not actually been
initialized with a pointer (possibly a nil pointer) in that function.
The most important part is interfaces: precisestack means
that if reading an interface value, the interface value is guaranteed
to be initialized, meaning that the type word can be relied
upon to be either nil or a valid interface type word describing
the data word.
This requires additional zeroing of certain values on the stack
on entry, which right now costs about 5% overall execution
time in all.bash. That cost will come down before Go 1.3
(issue 7345).
There are at least two known garbage collector bugs right now,
issues 7343 and 7344. The first happens even without precisestack.
The second I have only seen with precisestack, but that does not
mean that precisestack is what causes it. In fact it is very difficult
to explain by what precisestack does directly. Precisestack may
be exacerbating an existing problem. Both of those issues are
marked for Go 1.3 as well.
The reasons for enabling precisestack now are to give it more
time to soak and because the copying stack work depends on it.
LGTM=r
R=r
CC=golang-codereviews, iant, khr
https://golang.org/cl/64100044
»»»
TBR=r
CC=golang-codereviews
https://golang.org/cl/65230043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aad23e708c55f063a64eaa055e8d9d6c2294c9f4
元コミット内容
このコミットは、CL 64100044
(ハッシュ 04d062c2e81c
) で行われた変更を取り消すものです。元のコミットの目的は、Goランタイムにおいて「precisestack」機能をデフォルトで有効にすることでした。
元のコミットメッセージによると、precisestack
はスタックのガベージコレクションを完全に正確にするための機能です。これにより、スタックフレームの収集時に「使用されているが設定されていない」エラー("used and not set"
errors)が発生せず、ガベージコレクタがポインタを読み取る際に、そのスタックワードが実際にポインタ(nilポインタを含む)で初期化されていないという状況がなくなります。
特に重要なのはインターフェースの扱いでした。precisestack
が有効な場合、インターフェース値が初期化されていることが保証され、その型ワードがnilであるか、データワードを記述する有効なインターフェース型ワードであるかのいずれかとして信頼できるようになります。
この機能の有効化には、関数エントリ時にスタック上の一部の値を追加でゼロクリアする必要があり、その時点ではall.bash
テストスイート全体の実行時間に約5%のオーバーヘッドが発生していました。このコストはGo 1.3のリリースまでに削減される予定でした(issue 7345)。
また、precisestack
の有効化時には、少なくとも2つの既知のガベージコレクタのバグ(issue 7343と7344)が存在していました。issue 7343はprecisestack
がなくても発生するものでしたが、issue 7344はprecisestack
が有効な場合にのみ確認されており、precisestack
が既存の問題を悪化させている可能性が指摘されていました。これらの問題もGo 1.3で修正される予定でした。
precisestack
をデフォルトで有効にする理由は、より多くのテスト期間(soak time)を確保するためと、コピー型スタック(copying stack)の実装がこの機能に依存していたためと説明されています。
変更の背景
元のコミット(CL 64100044
)でprecisestack
をデフォルトで有効にした後、32ビットビルドが破損するという問題が発生しました。このコミット(CL 65230043
)は、その問題を解決するために、precisestack
のデフォルト有効化を取り消すことを目的としています。これは、新機能の導入が予期せぬ副作用(特に特定のアーキテクチャでのビルド失敗)を引き起こした場合に、安定性を優先して一時的に変更をロールバックするという、ソフトウェア開発における一般的なプラクティスです。
Go 1.3のリリースに向けて、ガベージコレクタの改善とスタック管理の精密化は重要な目標でしたが、その過程で発生した互換性の問題に対処する必要がありました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の内部動作に関する知識が役立ちます。
- Goのガベージコレクション (GC): Goはトレース型ガベージコレクタを使用しており、プログラムが使用しているメモリ(到達可能なオブジェクト)を特定し、それ以外のメモリを解放します。GCはスタック、ヒープ、グローバル変数などをスキャンしてポインタを識別し、到達可能性を判断します。
- スタックとポインタ: Goの関数呼び出しでは、ローカル変数や引数がスタック上に配置されます。これらの変数の中には、ヒープ上のオブジェクトを指すポインタが含まれることがあります。GCが正確に動作するためには、スタック上のどのワードがポインタであり、どのワードがポインタではないかを正確に識別する必要があります。
- 「Used and not set」エラー: これは、ガベージコレクタがスタック上のメモリ領域をスキャンする際に、まだ有効な値が設定されていない(初期化されていない)にもかかわらず、ポインタとして解釈しようとすることで発生する可能性のある問題です。これにより、GCが不正なメモリをたどったり、クラッシュしたりする可能性があります。
- インターフェース (Interface): Goのインターフェースは、型と値のペアとして内部的に表現されます。型はインターフェースが保持する具体的な型の情報、値はその具体的な型のインスタンスへのポインタです。GCがインターフェース値を正確に処理するためには、この型と値のペアが常に有効な状態であることが重要です。特に、型ワードがnilであるか、有効な型情報を含んでいる必要があります。
GOEXPERIMENT
環境変数: Goのビルドシステムでは、GOEXPERIMENT
環境変数を使用して、実験的な機能や開発中の機能を有効/無効にすることができます。これにより、新しい機能をデフォルトで有効にする前に、特定の環境でテストを行うことが可能になります。- Goのビルドプロセス (
cmd/gc
):cmd/gc
はGoのコンパイラであり、Goのソースコードを機械語に変換します。このプロセスには、スタックフレームのレイアウトやガベージコレクションに関するメタデータの生成も含まれます。 - Goのランタイム (
src/pkg/runtime
): Goのランタイムは、ガベージコレクタ、スケジューラ、メモリ管理など、Goプログラムの実行をサポートする低レベルのコードを含んでいます。
技術的詳細
このコミットは、precisestack
機能のデフォルト有効化を取り消すことで、32ビットビルドの破損を修正します。
precisestack
は、スタック上のポインタの識別精度を高めるための機能です。従来のGoのGCでは、スタック上のポインタを識別する際に、一部のヒューリスティックや保守的なアプローチが用いられることがありました。これは、パフォーマンス上の理由や、コンパイラがスタック上のすべてのメモリワードの正確な状態を常に追跡するのが困難であるためです。しかし、このアプローチは「used and not set」エラーのような問題を引き起こす可能性がありました。
precisestack
が目指したのは、関数エントリ時にスタック上の特定の領域をゼロクリアするなどして、スタック上のすべてのポインタ候補が常に既知の状態(有効なポインタかnilポインタ)であることを保証することです。これにより、GCはスタックをスキャンする際に、どのワードがポインタであるかを確実に識別できるようになり、ガベージコレクションの正確性と信頼性が向上します。特にインターフェース値の正確な処理は、Goの型システムとGCの健全性にとって非常に重要です。
しかし、この「追加のゼロクリア」やスタックフレームの管理方法の変更が、32ビットアーキテクチャの特定のコンパイルパスやランタイムの挙動と衝突し、ビルドが失敗する原因となったと考えられます。32ビットシステムでは、ポインタのサイズやアラインメント、レジスタの使用方法などが64ビットシステムとは異なるため、低レベルの最適化やメモリ管理の変更が予期せぬ問題を引き起こすことがあります。
このコミットでは、precisestack
をデフォルトで有効にする設定を元に戻し、GOEXPERIMENT
環境変数を通じて明示的に有効にした場合にのみ機能するように変更しています。これにより、32ビットビルドの破損を回避しつつ、開発者がprecisestack
のテストを継続できるようにしています。
コアとなるコードの変更箇所
このコミットによる変更は、以下の2つのファイルにわたります。
-
src/cmd/gc/lex.c
:setexp
関数内で、precisestack_enabled = 1; // on by default
という行が削除されました。- この変更により、コンパイラ側で
precisestack
がデフォルトで有効になる設定が取り消されます。
-
src/pkg/runtime/proc.c
:runtime·schedinit
関数内で、runtime·precisestack = true; // haveexperiment("precisestack");
という行が、runtime·precisestack = haveexperiment("precisestack");
に変更されました。- この変更により、ランタイム側で
precisestack
の有効/無効が、ハードコードされたtrue
ではなく、haveexperiment("precisestack")
関数の結果(つまりGOEXPERIMENT
環境変数の設定)に依存するようになります。
コアとなるコードの解説
src/cmd/gc/lex.c
の変更
src/cmd/gc/lex.c
はGoコンパイラの字句解析器(lexer)の一部であり、コンパイル時の実験的フラグ(GOEXPERIMENT
)の処理も行います。
setexp
関数は、GOEXPERIMENT
環境変数の値を解析し、対応する実験的機能を有効にする役割を担っています。
元のコードでは、precisestack_enabled = 1; // on by default
という行が明示的に存在し、GOEXPERIMENT
の設定に関わらずprecisestack
をデフォルトで有効にしていました。これは、precisestack
をGo 1.3のデフォルト機能として導入するためのステップでした。
このコミットでは、この行を削除することで、precisestack
のデフォルト有効化を取り消しています。これにより、precisestack
はGOEXPERIMENT
にprecisestack
が指定された場合にのみ有効になるように戻されます。
src/pkg/runtime/proc.c
の変更
src/pkg/runtime/proc.c
はGoランタイムのプロセッサ(P)とスケジューラ(M)の初期化に関連するコードを含んでいます。
runtime·schedinit
関数は、ランタイムの初期化処理の早い段階で呼び出されます。
元のコードでは、runtime·precisestack = true;
と直接true
が代入されており、ランタイムレベルでもprecisestack
が常に有効になるように設定されていました。コメントアウトされた// haveexperiment("precisestack");
は、この行が以前はGOEXPERIMENT
に依存していたが、デフォルト有効化のために変更されたことを示唆しています。
このコミットでは、この行をruntime·precisestack = haveexperiment("precisestack");
に戻しています。haveexperiment
関数は、GOEXPERIMENT
環境変数に特定の文字列(この場合は"precisestack"
)が含まれているかどうかをチェックします。この変更により、ランタイムのprecisestack
フラグは、コンパイラと同様に、GOEXPERIMENT
の設定に依存するようになります。
これらの変更は、precisestack
をデフォルトで有効にするという方針を一時的に撤回し、32ビットビルドの安定性を優先するためのものです。これにより、開発者は引き続きGOEXPERIMENT=precisestack
を設定することでこの機能をテストできますが、デフォルトのビルドでは無効になります。
関連リンク
- 元のコミット (CL 64100044): https://golang.org/cl/64100044
- このコミット (CL 65230043): https://golang.org/cl/65230043
- Go Issue 7345 (precisestackのコスト削減): https://golang.org/issue/7345
- Go Issue 7343 (GCバグ): https://golang.org/issue/7343
- Go Issue 7344 (GCバグ): https://golang.org/issue/7344
参考にした情報源リンク
- Go言語の公式ドキュメントおよびソースコード
- GoのIssueトラッカー
- Goのコードレビューシステム (Gerrit)
- Goのガベージコレクションに関する一般的な情報源 (例: "Go's Garbage Collector: From 1.3 to 1.5" by Rick Hudson, "The Go Programming Language" by Alan A. A. Donovan and Brian W. Kernighan)
- 32ビットアーキテクチャと64ビットアーキテクチャにおけるコンパイラとランタイムの挙動の違いに関する一般的な知識