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

[インデックス 18716] ファイルの概要

このコミットは、GoランタイムにおけるCBARGSマクロの定義をnacl/amd64p32アーキテクチャ向けに更新するものです。具体的には、nacl/amd64p32環境ではCBARGSが使用されないことを明示するために、その定義をnilに変更しています。

コミット

commit 13ab78fdd995cf328c341d86cdcffd154e3441b7
Author: Dave Cheney <dave@cheney.net>
Date:   Tue Mar 4 10:36:04 2014 +1100

    runtime: update CBARGS macro for nacl/amd64p32
    
    CBARGS is unused on amd64p32 so make this explicit.
    
    LGTM=bradfitz
    R=rsc, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/70940043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/13ab78fdd995cf328c341d86cdcffd154e3441b7

元コミット内容

runtime: update CBARGS macro for nacl/amd64p32

CBARGS is unused on amd64p32 so make this explicit.

LGTM=bradfitz
R=rsc, bradfitz
CC=golang-codereviews
https://golang.org/cl/70940043

変更の背景

この変更の背景には、Goランタイムがサポートする様々なアーキテクチャと、Cgo(GoとC言語の相互運用機能)の利用状況があります。src/pkg/runtime/cgocall.cファイルは、Cgoコールバック(C言語からGo言語の関数を呼び出す際)の処理に関連するコードを含んでいます。

以前のコードでは、nacl/amd64p32アーキテクチャ向けにCBARGSマクロが定義されていましたが、コメントには「There is no cgo support for nacl/amd64p32 but we need to have something here so use the amd64 value as a placeholder.」(nacl/amd64p32にはCgoサポートがないが、ここに何かを置く必要があるので、amd64の値をプレースホルダーとして使用する)とありました。

このコミットは、この状況をより正確に反映させることを目的としています。nacl/amd64p32環境ではCgoがサポートされていないため、CBARGSマクロが実際に使用されることはありません。したがって、その定義をnilにすることで、コードの意図を明確にし、将来的な誤解や不必要なコードパスの評価を防ぐことができます。これは、未使用のコードパスを明示的に無効化することで、コードの保守性と理解度を向上させる典型的な例です。

前提知識の解説

Cgo

Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。Cgoを使用すると、GoのガベージコレクタとCのメモリ管理の間でデータの受け渡しを調整する必要があるため、ランタイムレベルでの特別な処理が必要になります。

src/pkg/runtime/cgocall.c

このファイルは、Goランタイムの一部であり、Cgoのコールバックメカニズム、特にC言語からGo言語への呼び出しに関連する低レベルの処理を扱っています。GoとCの間でスタックフレームやレジスタの状態を適切に管理し、関数呼び出しのコンテキストを切り替える役割を担っています。

CBARGSマクロ

CBARGSは "Callback Arguments" の略で、C言語からGo言語の関数が呼び出された際に、そのGo関数に渡される引数へのポインタを計算するためのマクロです。Cgoコールバックでは、CのスタックフレームからGoの関数が期待する引数を取得する必要があります。このマクロは、現在のGoルーチンのスタックポインタ(m->g0->sched.sp)を基準に、引数が格納されているメモリ上のオフセットを計算します。

nacl/amd64p32

naclは「Native Client」の略で、Googleが開発したWebブラウザ内でネイティブコードを実行するためのサンドボックス技術です。amd64p32は、64ビットのAMD64アーキテクチャをベースにしながら、ポインタサイズが32ビットに制限されている特殊な環境を指します。これは、メモリ使用量を抑えつつ、64ビットCPUの性能を活用するために設計されたものです。Native Clientは、セキュリティ上の理由から、通常のシステムコールやCgoのような外部コードとの連携に厳しい制限を課しています。このため、nacl/amd64p32環境ではCgoがサポートされていない、あるいはその機能が大幅に制限されているのが一般的です。

m->g0->sched.sp

Goランタイムでは、各Goルーチン(goroutine)はg構造体で表現され、その中にスケジューリング情報が含まれています。mは「Machine」の略で、OSのスレッドに対応するGoランタイムの抽象化です。m->g0は、現在のM(OSスレッド)に紐付けられたシステムルーチン用のGoルーチン(g0)を指します。g0->sched.spは、このシステムルーチンのスタックポインタ(Stack Pointer)を示しており、低レベルのランタイム操作やCgoコールバックにおいて、スタック上のデータにアクセスするために使用されます。

技術的詳細

このコミットの技術的な核心は、CBARGSマクロの定義を、特定のアーキテクチャ(nacl/amd64p32)において、その機能が不要であることを明示的に示すように変更した点です。

元のコードでは、nacl/amd64p32向けにCBARGSが以下のように定義されていました。

// There is no cgo support for nacl/amd64p32 but we need to have something here 
// so use the amd64 value as a placeholder.
#ifdef GOARCH_amd64p32
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
#endif

この定義は、amd64アーキテクチャのCBARGS定義と同じものであり、コメントで「Cgoサポートがないが、プレースホルダーとして必要」と説明されていました。しかし、実際にCgoがサポートされていないのであれば、このマクロが計算するアドレスは意味を持ちませんし、誤って使用される可能性も排除できません。

今回の変更では、この定義を以下のように修正しました。

// Unimplemented on amd64p32
#ifdef GOARCH_amd64p32
#define CBARGS (CallbackArgs*)(nil)
#endif

これにより、nacl/amd64p32環境でCBARGSが参照された場合、それはnilポインタとして扱われることになります。これは、この環境ではCgoコールバックの引数構造体が存在しない、あるいはアクセスできないことを明確に示します。

この変更の利点は以下の通りです。

  1. 明確性: nacl/amd64p32におけるCBARGSの役割が「未実装」または「使用不可」であることがコードレベルで明確になります。
  2. 安全性: nilに定義することで、誤ってこのマクロが使用された場合に、早期にnilポインタデリファレンスなどのエラーが発生し、問題が特定しやすくなります。以前のプレースホルダーの定義では、無効なメモリ領域を指す可能性があり、デバッグが困難な未定義動作につながる可能性がありました。
  3. 最適化の可能性: コンパイラやリンカが、CBARGSnilであることを認識し、関連する未使用のコードパスをより効果的に最適化(デッドコード排除など)できる可能性があります。

この変更は、Goランタイムのコードベースにおける正確性と堅牢性を高めるための、細かではあるが重要な改善と言えます。

コアとなるコードの変更箇所

変更はsrc/pkg/runtime/cgocall.cファイルの一箇所のみです。

--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -223,10 +223,9 @@ struct CallbackArgs
 #define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))\n #endif\n \n-// There is no cgo support for nacl/amd64p32 but we need to have something here \n-// so use the amd64 value as a placeholder.\n+// Unimplemented on amd64p32\n #ifdef GOARCH_amd64p32\n-#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))\n+#define CBARGS (CallbackArgs*)(nil)\n #endif\n \n // On 386, stack frame is three words, plus caller PC.\n```

## コアとなるコードの解説

変更された行は以下の通りです。

```c
#ifdef GOARCH_amd64p32
-#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
+#define CBARGS (CallbackArgs*)(nil)
#endif

これはプリプロセッサディレクティブ#ifdef GOARCH_amd64p32によって囲まれており、コンパイルターゲットがnacl/amd64p32アーキテクチャである場合にのみ有効になります。

  • 変更前: CBARGSマクロは、m->g0->sched.sp(現在のシステムルーチンのスタックポインタ)から特定のオフセット(2*sizeof(void*))を計算し、それをCallbackArgs*型にキャストしていました。これは、amd64アーキテクチャにおけるCgoコールバック引数の一般的な配置を模倣したものでしたが、nacl/amd64p32ではCgoがサポートされていないため、この計算結果は意味をなしませんでした。
  • 変更後: CBARGSマクロは、単にnilポインタをCallbackArgs*型にキャストするように変更されました。これにより、nacl/amd64p32環境ではCBARGSが常にnilを返すようになり、このマクロが使用されるべきではないという意図がコードに明示的に埋め込まれました。

この変更は、Goランタイムのクロスプラットフォーム対応における細かな調整であり、特定の環境でのCgoのサポート状況を正確に反映させるためのものです。

関連リンク

参考にした情報源リンク