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

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

このコミットは、Go言語のランタイムにおけるメモリ管理関連のヘッダーファイル src/runtime/malloc.h から、重複する typedef 宣言を削除するものです。これにより、コードの冗長性が排除され、可読性と保守性が向上します。

コミット

commit 7843a14df1b53d3500b9ef61d53ccf7d64f40921
Author: Ian Lance Taylor <iant@golang.org>
Date:   Thu Jan 8 09:45:42 2009 -0800

    Remove duplicate typedef declarations.
    
    R=rsc
    DELTA=7  (0 added, 7 deleted, 0 changed)
    OCL=22267
    CL=22281

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

https://github.com/golang/go/commit/7843a14df1b53d3500b9ef61d53ccf7d64f40921

元コミット内容

重複する typedef 宣言を削除しました。

変更の背景

この変更は、Go言語のランタイムコードベースにおけるクリーンアップとリファクタリングの一環です。C言語の慣習では、構造体を定義する際に struct MyStruct { ... }; と定義した後、その構造体を MyStruct という名前で直接参照できるようにするために typedef struct MyStruct MyStruct; のように typedef を使用することが一般的でした。しかし、C++では struct MyStruct { ... }; と定義するだけで MyStruct を型名として直接使用できます。Go言語のランタイムはC言語で書かれていましたが、このコミットが行われた2009年当時、Goのコンパイラやツールチェインは進化の途上にあり、C言語のコードスタイルとGoのコードスタイルが混在している部分がありました。

このコミットの背景にあるのは、struct の定義と typedef 宣言が同じファイル内で連続して記述されており、typedef が実質的に冗長になっていた状況を解消することです。特に、struct の定義が typedef の直後に続く場合、typedef は不要であり、コードの行数を増やし、わずかながらコンパイル時間を増加させる要因となります。このような重複を削除することで、コードベースをより簡潔にし、将来的なメンテナンスを容易にすることが目的です。

前提知識の解説

C言語における typedefstruct

C言語では、構造体を定義する際に struct キーワードを使用します。例えば、以下のように定義します。

struct MyStruct {
    int data;
    char name[20];
};

この MyStruct 型の変数を宣言する際には、常に struct MyStruct myVar; のように struct キーワードを前置する必要があります。これを省略して MyStruct myVar; のように宣言できるようにするために typedef が使用されます。

typedef struct MyStruct MyStruct; // MyStruct を struct MyStruct の別名として定義

この typedef 宣言と構造体定義を組み合わせると、以下のようになります。

typedef struct MyStruct {
    int data;
    char name[20];
} MyStruct; // 構造体定義と同時に typedef を行う

または、今回のコミットで削除された形式のように、別々に定義されることもあります。

typedef struct MyStruct MyStruct; // まず typedef
struct MyStruct { // その後で struct の詳細を定義
    int data;
    char name[20];
};

今回のコミットでは、後者の形式で typedef 宣言と struct 定義が連続して存在し、typedef が冗長になっていたケースが対象です。

Go言語のランタイムとメモリ管理

Go言語のランタイムは、ガベージコレクション、スケジューリング、メモリ管理など、Goプログラムの実行を支える低レベルな機能を提供します。初期のGoランタイムはC言語で書かれており、その後Go言語自体に移植されていきました。

src/runtime/malloc.h は、Goランタイムのメモリ管理システム、特にヒープアロケータに関連するデータ構造と関数宣言を含むヘッダーファイルです。このファイルには、以下のような主要なメモリ管理コンポーネントの定義が含まれています。

  • FixAlloc: 固定サイズのオブジェクトを効率的に割り当てるためのアロケータ。
  • MCentral: 特定のサイズクラスのオブジェクトのフリーリストを管理する中央リスト。
  • MCache: 各ゴルーチン(またはP)が持つローカルなキャッシュで、ロックなしでオブジェクトを割り当てられるようにするもの。
  • MHeap: Goランタイムのグローバルなヒープを管理する構造体。ページ単位でメモリを管理し、MCentral にページを供給します。
  • MStats: メモリ統計情報を保持する構造体。
  • MHeapMap / MHeapMapCache: ヒープ内のアドレスから対応する MSpan を検索するためのデータ構造。

これらの構造体は、Goのガベージコレクタと連携して、プログラムが効率的にメモリを使用できるようにします。

技術的詳細

このコミットの技術的詳細は、C言語の typedef の使用法と、Goランタイムのコードベースにおけるその適用に焦点を当てています。

Goランタイムの src/runtime/malloc.h ファイルでは、いくつかの構造体について、以下のような形式で typedef 宣言が行われていました。

typedef struct MCache MCache;
struct MCache
{
    // ... 構造体のメンバー ...
};

この形式では、typedef struct MCache MCache;struct MCacheMCache という名前で参照できるようにする別名を定義しています。しかし、その直後に struct MCache { ... }; という実際の構造体定義が続いています。

C言語の標準では、struct MCache { ... }; と定義された後でも、struct MCache と書く必要があります。しかし、多くのCコンパイラ(特にC++のコンパイラや、C99以降のCコンパイラの一部)では、struct MCache { ... }; と定義された時点で、MCache という名前がタグとしてだけでなく、型名としてもスコープに入るため、MCache と直接記述できるようになります。

Goランタイムのビルドプロセスで使用されるコンパイラ(おそらくGCCなど)がこの挙動をサポートしていたため、typedef struct Name Name; という明示的な typedef 宣言は冗長となっていました。このコミットは、この冗長な typedef 宣言を削除することで、コードの重複をなくし、ファイルサイズを削減し、わずかながらコンパイル時の処理を減らすことを目的としています。

削除された typedef 宣言は以下の通りです。

  • typedef struct MCache MCache;
  • typedef struct MStats MStats;
  • typedef struct MCentral MCentral;
  • typedef struct MHeapMap MHeapMap;
  • typedef struct MHeapMapCache MHeapMapCache;
  • typedef struct MHeap MHeap;
  • typedef struct FixAlloc FixAlloc; (これはdiffには含まれていませんが、同様のパターンで存在していた可能性があります。diffでは7行削除とあるので、MCache, MStats, MCentral, MHeapMap, MHeapMapCache, MHeap の6つと、もう一つ何か、あるいは行の数え方の違いかもしれません。)

これらの typedef 宣言の削除は、コードの機能に影響を与えるものではなく、純粋にコードのクリーンアップと最適化です。

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

変更は src/runtime/malloc.h ファイルのみで行われました。具体的には、以下の7行が削除されました。

--- a/src/runtime/malloc.h
+++ b/src/runtime/malloc.h
@@ -73,7 +73,6 @@
 
 typedef struct FixAlloc	FixAlloc;
 typedef struct MCentral	MCentral;
-typedef struct MCache	MCache;
 typedef struct MHeap	MHeap;
 typedef struct MHeapMap	MHeapMap;
 typedef struct MHeapMapCache	MHeapMapCache;
@@ -148,7 +147,6 @@ void	FixAlloc_Free(FixAlloc *f, void *p);\n 
 // Statistics.\n // Shared with Go: if you edit this structure, also edit ../lib/malloc.go.\n-typedef struct MStats MStats;\n struct MStats\n {\n 	uint64	alloc;\n@@ -228,7 +226,6 @@ void	MSpanList_Remove(MSpan *span);\t// from whatever list it is in\n 
 \n // Central list of free objects of a given size.\n-typedef struct MCentral MCentral;\n struct MCentral\n {\n 	Lock;\n@@ -256,7 +253,6 @@ void	MCentral_FreeList(MCentral *c, int32 n, MLink *first);\n // On the other hand, it\'s just virtual address space: most of\n // the memory is never going to be touched, thus never paged in.\n \n-typedef struct MHeapMap MHeapMap;\n typedef struct MHeapMapNode2 MHeapMapNode2;\n typedef struct MHeapMapNode3 MHeapMapNode3;\n \n@@ -319,7 +315,6 @@ enum\n 	MHeapMapCache_HashBits = 12\n };\n \n-typedef struct MHeapMapCache MHeapMapCache;\n struct MHeapMapCache\n {\n 	uintptr array[1<<MHeapMapCache_HashBits];\n@@ -341,7 +341,6 @@ struct MHeapMapCache\n // Main malloc heap.\n // The heap itself is the \"free[]\" and \"large\" arrays,\n // but all the other global data is here too.\n-typedef struct MHeap MHeap;\n struct MHeap\n {\n 	Lock;\n```

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

削除された各行は、`typedef struct <StructName> <StructName>;` という形式の宣言です。これらの宣言は、対応する `struct <StructName> { ... };` の定義が直後に続くため、冗長でした。

例えば、`MCache` の場合:

削除前:
```c
typedef struct MCache MCache;
typedef struct MHeap MHeap;
// ...
typedef struct MCache MCache; // この行が削除された
struct MCache
{
    // ...
};

削除後:

typedef struct MHeap MHeap;
// ...
struct MCache // struct MCache の定義は残る
{
    // ...
};

同様に、MStats, MCentral, MHeapMap, MHeapMapCache, MHeap についても、対応する typedef 宣言が削除されました。これらの typedef は、C言語の古い慣習や、特定のコンパイラの挙動に依存しないようにするためのものでしたが、Goランタイムのビルド環境では不要と判断されたため削除されました。

この変更は、コードのセマンティクス(意味)や機能に一切影響を与えません。単に、同じ型を二重に宣言していた部分を整理し、コードベースをよりクリーンで効率的なものにするためのものです。

関連リンク

特になし。このコミットはGoランタイムの内部的なクリーンアップであり、外部ドキュメントや仕様に直接関連するものではありません。

参考にした情報源リンク

  • C言語の typedefstruct に関する一般的な知識
  • Go言語の初期のランタイム実装に関する一般的な知識 (特にC言語で書かれていた時期)
  • Gitのコミットログと差分表示