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

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

このコミットは、Go言語の初期開発段階における重要なリファクタリングとアーキテクチャ変更を示しています。主に、浮動小数点演算に関連するルーチンをsysパッケージからmathパッケージへ移動し、GoとC言語間のインターフェースにCgoを導入することで、手書きのラッパーを置き換えています。これにより、コードのモジュール性、保守性、そして将来的な拡張性が向上しています。

コミット

commit 1f8a40d85c3bb7a1cf3113e7ab1afdb44f6c0e4d
Author: Russ Cox <rsc@golang.org>
Date:   Thu Jan 22 16:23:44 2009 -0800

    move math routines from package sys to package math,
    though they still build in src/runtime.
    
    use cgo instead of hand-written wrappers.
    
    R=r
    DELTA=740  (289 added, 300 deleted, 151 changed)
    OCL=23326
    CL=23331

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

https://github.com/golang/go/commit/1f8a40d85c3bb7a1cf3113e7ab1afdb44f6c0e4d

元コミット内容

このコミットの元のメッセージは以下の通りです。

「mathルーチンをsysパッケージからmathパッケージへ移動。ただし、これらは引き続きsrc/runtimeでビルドされる。手書きのラッパーの代わりにCgoを使用する。」

変更の背景

Go言語の初期段階では、多くの低レベルなシステム関連関数やランタイム内部関数がsysパッケージに集約されていました。これには、浮動小数点演算に関する関数も含まれていました。しかし、このような設計は、関心の分離の原則に反し、コードの可読性、保守性、そして再利用性を低下させる可能性がありました。

このコミットの主な背景は以下の2点です。

  1. モジュール性の向上: 浮動小数点演算は一般的な数学操作であり、システムコールやランタイムの内部処理とは異なるドメインに属します。これらを専用のmathパッケージに分離することで、Go標準ライブラリの構造をより論理的かつ整理されたものにし、開発者が特定の機能を見つけやすく、利用しやすくすることを目指しました。
  2. Cgoの導入と手書きラッパーの置き換え: Go言語は、C言語で書かれた既存のライブラリと連携するためのメカニズムを必要としていました。初期には手書きのC言語ラッパーやアセンブリコードが使用されることもありましたが、これは開発コストが高く、移植性にも課題がありました。Cgoは、GoコードからC関数を直接呼び出すための公式なツールであり、より安全で効率的な相互運用性を提供します。このコミットは、浮動小数点演算ルーチンにおいてCgoを本格的に採用し、将来的に他のシステムレベルの機能にもCgoを適用するための布石となりました。これにより、GoのランタイムがCライブラリの機能をより柔軟に利用できるようになり、特にOS固有の機能や高性能な数値計算ライブラリとの連携が容易になりました。

前提知識の解説

このコミットを理解するためには、以下の概念が重要です。

  • Go言語のパッケージシステム: Go言語は、コードを論理的に分割し、再利用性を高めるためにパッケージシステムを採用しています。sysmathはGoの標準パッケージの一部です。
  • Goランタイム (runtime): Goプログラムの実行を管理する低レベルなコード群です。ガベージコレクション、スケジューリング、システムコールなどが含まれます。Goの標準ライブラリの一部であるmathパッケージの関数であっても、その実装が最終的にランタイム内のCコードに依存することは珍しくありません。
  • 浮動小数点演算 (Floating-Point Arithmetic): コンピュータで実数を近似的に表現し、計算するための方法です。IEEE 754標準が広く用いられており、NaN (Not a Number) や Inf (Infinity) といった特殊な値も定義されています。これらの特殊な値の扱いも、数学関数の正確性には不可欠です。
  • Cgo: Go言語の機能の一つで、GoプログラムからC言語の関数を呼び出したり、C言語のコードをGoプログラムに組み込んだりするためのツールです。Cgoを使用すると、Goのソースファイル内にCコードを直接記述したり、既存のCライブラリをリンクしたりできます。これにより、Go言語だけでは実現が難しい低レベルな操作や、既存の高性能なCライブラリの利用が可能になります。Cgoは、GoとCの間のデータ変換や関数呼び出しの橋渡しを自動的に行います。
  • 手書きのラッパー (Hand-written wrappers): Cgoが成熟する以前や、特定のパフォーマンス要件がある場合に、GoとCの間のインターフェースを手動で記述したコードのことです。これには、Goの関数からCの関数を呼び出すためのアセンブリコードや、Goのデータ構造をCのデータ構造に変換するCコードなどが含まれます。Cgoに比べて開発が複雑でエラーを起こしやすく、移植性も低いという欠点があります。
  • src/cmd/gc: Goコンパイラ(gc)のソースコードがあるディレクトリです。Goの組み込み関数や型に関する情報が定義されています。sys.gosysimport.cは、コンパイラがGoの組み込み関数を認識するために使用されていました。
  • Makefile: ビルドプロセスを自動化するためのファイルです。Goの初期のビルドシステムでは、Makefileが広く使われていました。

技術的詳細

このコミットの技術的な変更は多岐にわたりますが、主要なポイントは以下の通りです。

  1. 浮動小数点ルーチンの移動:

    • これまでsrc/runtime/runtime.cに直接実装されていたfloat32tobits, float64tobits, float64frombits, float32frombits, isInf, NaN, isNaN, Inf, frexp, ldexp, modfといった浮動小数点関連のC関数が、新しく作成されたsrc/runtime/float.cに移動されました。
    • これらの関数は、Goのmathパッケージから利用されることを想定しています。
    • src/cmd/gc/sys.goおよびsrc/cmd/gc/sysimport.cから、これらの浮動小数点関連関数の宣言が削除されました。これは、これらの関数がもはやsysパッケージの組み込み関数として扱われないことを意味します。
  2. CgoによるGo-Cインターフェースの確立:

    • 新しくsrc/runtime/float_go.cgoファイルが導入されました。このファイルはCgoの構文を使用して、src/runtime/float.cで定義されたC関数(frexp, ldexp, modf, isInf, isNaN, Inf, NaN, float32tobits, float64tobits, float32frombits, float64frombits)をGoのmathパッケージの関数としてエクスポートしています。
    • 同様に、src/runtime/sema_go.cgoが導入され、セマフォ関連のC関数(semacquire, semrelease)をGoのsyncパッケージに公開しています。
    • これにより、GoのコードはCgoを介してこれらの低レベルなC関数を呼び出すことができるようになり、手書きのラッパーが不要になりました。
  3. mathパッケージの内部変更:

    • src/lib/mathディレクトリ内の既存のGoファイル(asin.go, exp.go, floor.go, fmod.go, log.go, pow.go, sin.go, sqrt.go, tan.goなど)は、これまでsys.Frexpsys.Modfのようにsysパッケージの関数を直接参照していた箇所を、Cgoを介して公開されたmathパッケージ内の同名の関数(例: Frexp(), Modf())に置き換えました。これにより、mathパッケージが自己完結性を高め、外部のsysパッケージへの依存を減らしました。
    • src/lib/math/Makefileが大幅に修正され、float.cfloat_go.cgoのコンパイルとリンクが組み込まれました。また、オブジェクトファイルのグループ化(O1, O2, O3, O4)が再編成され、ビルドの依存関係が更新されました。
  4. strconvパッケージの変更:

    • src/lib/strconv/atof.gosrc/lib/strconv/ftoa.goでは、浮動小数点数のビット表現を扱う関数(sys.Float32frombits, sys.Float64frombits, sys.Float32bits, sys.Float64bits)が、新しくmathパッケージからインポートされたmath.Float*bits関数に置き換えられました。これにより、strconvパッケージもmathパッケージの新しいインターフェースを利用するようになりました。
  5. cgo2cツールの改善:

    • src/runtime/cgo2c.cは、Cgoの処理を行う内部ツールです。このコミットでは、エラーメッセージの改善(ファイル名と行番号の表示)や、コマンドライン引数の解析方法の変更が行われました。これは、Cgoツールの堅牢性を高めるための改善です。
  6. セマフォ実装の変更 (Darwin/amd64):

    • src/runtime/amd64_darwin.hsrc/runtime/rt1_amd64_darwin.cでは、Darwin (macOS) 上でのセマフォ関連の関数名がsemcreateからmach_semcreateのように変更されました。これは、MachカーネルのセマフォAPIをより明示的に参照するためと考えられます。
    • src/runtime/sema.cでは、Goのsyncパッケージから呼び出されるセマフォ関数(semacquire, semrelease)のC実装が、sync·semacquireからsemacquireへと名前が変更されました。これは、CgoによってGoから直接呼び出されるC関数としての命名規則に合わせたものと推測されます。

これらの変更は、Go言語の初期設計において、低レベルなランタイム機能と高レベルな標準ライブラリ機能の間の境界を明確にし、Cgoを介したよりクリーンなインターフェースを確立しようとする意図を強く示しています。

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

このコミットのコアとなる変更は、主に以下のファイルに集約されています。

  1. src/runtime/float.c (新規追加):

    • これまでsrc/runtime/runtime.cに散らばっていた浮動小数点関連のC関数(float32tobits, float64tobits, isInf, NaN, frexp, ldexp, modfなど)がここに集約されました。
    • これらの関数は、Goのmathパッケージが内部的に利用する低レベルな実装を提供します。
  2. src/runtime/float_go.cgo (新規追加):

    • Cgoのディレクティブ(#include "runtime.h")とGoの関数宣言を組み合わせることで、float.cで定義されたC関数をGoのmathパッケージの関数として公開しています。
    • 例:
      func Frexp(f float64) (frac float64, exp int32) {
      	frac = frexp(f, &exp);
      }
      
      このGo関数Frexpは、C言語のfrexp関数を呼び出しています。
  3. src/runtime/sema_go.cgo (新規追加):

    • 同様に、Cgoを使用してsemacquiresemreleaseというC関数をGoのsyncパッケージに公開しています。
  4. src/runtime/runtime.c (大幅な削除):

    • float.cに移動されたすべての浮動小数点関連のC関数がこのファイルから削除されました。これにより、runtime.cはより純粋なGoランタイムのコア機能に特化するようになりました。
  5. src/cmd/gc/sys.go および src/cmd/gc/sysimport.c:

    • sysパッケージから浮動小数点関連の関数宣言が削除されました。これにより、これらの関数はもはやGoコンパイラによってsysパッケージの組み込み関数として特別扱いされなくなりました。
  6. src/lib/math/*.go ファイル群:

    • sys.Frexpなどのsysパッケージへの直接的な参照が、mathパッケージ内で定義された(Cgoを介してC実装にルーティングされる)関数に置き換えられました。これにより、mathパッケージのGoコードが、Cgoを介して提供される新しいC実装を利用するようになりました。

コアとなるコードの解説

src/runtime/float.c

このファイルは、Goのmathパッケージが利用する浮動小数点演算の低レベルなC言語実装を提供します。 例えば、float64tobits関数は、float64型の値をそのIEEE 754標準のビット表現(uint64)に変換します。これは、浮動小数点数の内部構造を直接操作する必要がある場合(例: NaNInfの判定、ビット操作による指数部や仮数部の抽出)に不可欠です。 frexpldexpmodfといった関数は、それぞれ浮動小数点数を仮数部と指数部に分解したり、それらを再構築したり、整数部と小数部に分割したりする標準的な数学関数です。これらは、より複雑な数学関数(例: Log, Exp, Pow)の実装の基礎となります。 isInf, isNaN, Inf, NaN関数は、IEEE 754で定義される無限大や非数といった特殊な浮動小数点値を生成したり、それらを判定したりするためのものです。これらの関数は、数値計算の堅牢性を確保するために重要です。

src/runtime/float_go.cgo

このファイルは、GoとCの間の「橋渡し」の役割を担います。Cgoの構文(#include "runtime.h")を使ってCのヘッダーファイルをインクルードし、その後にGoの関数を定義します。これらのGo関数は、Cの関数を呼び出すための薄いラッパーとして機能します。 例えば、func Frexp(f float64) (frac float64, exp int32)というGoの関数は、内部でCのfrexp関数を呼び出し、その結果をGoの戻り値として返します。Cgoは、Goのfloat64型とCのdouble型、Goのint32型とCのint32_t型(または同等の型)の間で自動的に型変換を行います。 このアプローチにより、Goのmathパッケージは、C言語で最適化されたり、OS固有の機能を利用したりする低レベルな浮動小数点演算を、Goのコードから直接、かつ型安全な方法で利用できるようになります。

src/lib/math/*.go の変更

これらのファイルでは、これまでsysパッケージの関数を直接呼び出していた箇所が、mathパッケージ内で定義された(Cgoを介してC実装にルーティングされる)関数に置き換えられました。 例えば、src/lib/math/asin.goでは、sys.NaN()NaN()に、src/lib/math/exp.goではsys.IsNaN(x)IsNaN(x)に、sys.Inf(1)Inf(1)に、sys.Ldexp(y, k)Ldexp(y, k)に変更されています。 これにより、mathパッケージのGoコードは、sysパッケージという低レベルな依存関係から解放され、よりクリーンな依存関係グラフが構築されました。これは、Goの標準ライブラリの設計原則である「関心の分離」を強化するものです。

これらの変更は、Go言語が初期段階でどのように低レベルなシステム機能と高レベルなライブラリ機能を分離し、Cgoという強力なツールを導入して、より堅牢で保守性の高いコードベースを構築していったかを示す好例です。

関連リンク

参考にした情報源リンク