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

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

このコミットは、Go言語の型チェッカーである go/types パッケージにおける型サイズの計算、特に unsafe パッケージが提供する AlignofOffsetofSizeof と関連する処理の正確性と柔軟性を向上させるための重要な変更を含んでいます。主な目的は、これらのサイズ計算をプラットフォーム固有の要件に合わせてカスタマイズできるようにすること、定数計算における整数型のサイズを正確に反映させること、そして関連するロジックを sizes.go という新しいファイルに集約することです。また、文字列定数のスライスに関するバグも修正されています。

コミット

commit a5e42f2611e0daae92a699091ce8c6525e9dc5e9
Author: Robert Griesemer <gri@golang.org>
Date:   Mon Feb 25 22:06:58 2013 -0800

    go/types: fix sizeof computations
    
    Context.Alignof/Offsetsof/Sizeof now provide means
    to customize the type checker for a given platform.
    
    - provide Context.Offsetsof to specify the
      offsets of struct fields
    - use the correct sizes for ints, uint, uintptrs
      in constant computations
    - moved all size computations into separate file
      (sizes.go)
    - fixed a bug with string constant slicing
    
    R=adonovan, axwalk
    CC=golang-dev
    https://golang.org/cl/7363054

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

https://github.com/golang/go/commit/a5e42f2611e0daae92a699091ce8c6525e9dc5e9

元コミット内容

go/types: fix sizeof computations

Context.Alignof/Offsetsof/Sizeof now provide means
to customize the type checker for a given platform.

- provide Context.Offsetsof to specify the
  offsets of struct fields
- use the correct sizes for ints, uint, uintptrs
  in constant computations
- moved all size computations into separate file
  (sizes.go)
- fixed a bug with string constant slicing

変更の背景

Go言語の型システムは、メモリレイアウトや型のサイズ、アライメントに関する厳密なルールを持っています。特に unsafe パッケージの AlignofOffsetofSizeof 関数は、これらの低レベルなメモリ特性をプログラムから直接検査するために不可欠です。しかし、これらの計算は実行されるプラットフォーム(アーキテクチャ、OSなど)によって異なる場合があります。例えば、int 型のサイズは32ビットシステムと64ビットシステムで異なりますし、構造体のフィールドオフセットやアライメントも、コンパイラのパディング戦略によって変動する可能性があります。

このコミット以前は、go/types パッケージ内のサイズ計算ロジックが、特定のプラットフォームの仮定(例: ポインタサイズが64ビットであること)に強く依存しており、柔軟性に欠けていました。また、構造体のフィールドオフセットの計算が Struct 型の内部に直接保持されるなど、ロジックが分散していました。

この変更の背景には、以下の課題があったと考えられます。

  1. プラットフォーム依存性の問題: 型チェッカーが、異なるプラットフォームのメモリレイアウトを正確にモデル化するためのメカニズムが不足していた。これにより、クロスコンパイルや異なるアーキテクチャでの実行時に、unsafe 操作の結果が期待と異なる可能性がありました。
  2. 定数計算の不正確さ: intuintuintptr などの整数型定数の計算において、プラットフォーム固有のサイズが考慮されておらず、オーバーフローチェックなどが不正確になる可能性がありました。
  3. コードの分散と保守性: サイズ計算に関するロジックが builtins.goexpr.go など複数のファイルに散らばっており、保守性や拡張性が低い状態でした。
  4. 文字列定数スライスのバグ: 特定の条件下で文字列定数をスライスした際の型推論にバグが存在し、string 型ではなく untyped string のままになる問題がありました。

これらの課題を解決し、go/types パッケージの堅牢性と柔軟性を高めるために、本コミットのような抜本的な変更が必要とされました。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびコンパイラ関連の概念を理解しておく必要があります。

  1. Go言語の型システム:
    • 基本型 (Basic Types): int, uint, bool, string, float64 など。
    • 複合型 (Composite Types): array, slice, struct, interface, map, chan, func など。
    • 名前付き型 (Named Types): type MyInt int のように、既存の型に新しい名前を付けた型。
    • 基底型 (Underlying Type): 名前付き型の元となる型。例えば MyInt の基底型は int
  2. unsafe パッケージ:
    • Go言語の unsafe パッケージは、Goの型システムやメモリ安全性の保証をバイパスする機能を提供します。主に低レベルなシステムプログラミングや、特定のパフォーマンス最適化のために使用されます。
    • unsafe.Alignof(x): 変数 x のアライメントをバイト単位で返します。アライメントとは、メモリ上でデータが配置される際の特定の境界条件のことです。例えば、4バイトアライメントのデータは、アドレスが4の倍数である場所に配置されます。
    • unsafe.Offsetof(x.f): 構造体 x のフィールド f の、構造体の先頭からのオフセットをバイト単位で返します。
    • unsafe.Sizeof(x): 変数 x のメモリ上のサイズをバイト単位で返します。
    • これらの関数はコンパイル時に評価される定数式であり、実行時の値ではありません。
  3. 構造体 (Structs) のメモリレイアウト:
    • 構造体のフィールドは、宣言された順序でメモリに配置されますが、アライメント要件を満たすためにフィールド間にパディング(詰め物)が挿入されることがあります。これにより、構造体の実際のサイズは、各フィールドのサイズの合計よりも大きくなることがあります。
    • 埋め込みフィールド (Embedded Fields): 構造体内に型名のみでフィールドを宣言すると、その型のフィールドやメソッドが外側の構造体に「昇格」されます。これは、メモリレイアウトにも影響を与えます。
  4. 定数 (Constants):
    • Go言語の定数は、コンパイル時に値が決定される不変のエンティティです。型なし定数 (untyped constants) は、その値が表現可能な任意の型に変換できます。
    • 定数式は、コンパイル時に評価され、その結果も定数となります。
  5. go/types パッケージ:
    • Goの公式な型チェッカーライブラリです。GoコンパイラやIDE、リンターなどのツールで利用され、Goプログラムの型チェックを行います。
    • Context 構造体: 型チェックのコンテキストを保持する重要な構造体です。型チェック中に必要な情報(インポートパス、エラーハンドラなど)を提供します。このコミットでは、サイズ計算のカスタマイズポイントがここに追加されています。
    • operand 構造体: 型チェック中に式の評価結果(値、型、モードなど)を保持するために使用されます。
  6. Gerrit Change-ID (CL):
    • https://golang.org/cl/7363054 は、Goプロジェクトがコードレビューに利用しているGerritシステムにおける変更の識別子です。これはGitHubのプルリクエストに相当するもので、このコミットがGerrit上でどのようにレビューされ、承認されたかを示します。

これらの概念を理解することで、コミットがGoの型システムとコンパイラの内部にどのように影響を与え、どのような問題を解決しようとしているのかを深く把握できます。

技術的詳細

このコミットの技術的詳細は、主に go/types パッケージの Context 構造体の拡張、サイズ計算ロジックの再編成、および定数評価の改善に集約されます。

  1. Context 構造体の拡張とカスタマイズ可能なサイズ計算:

    • src/pkg/go/types/api.go にある Context 構造体に、以下の関数型フィールドが追加・修正されました。
      • Alignof func(Type) int64: 型のアライメントを決定するためのカスタム関数。デフォルトの DefaultAlignof が存在しない場合に呼び出されます。
      • Offsetsof func(fields []*Field) []int64: 構造体フィールドのオフセットを決定するための新しいカスタム関数。これにより、型チェッカーは特定のプラットフォームの構造体レイアウト規則を正確に反映できるようになります。
      • Sizeof func(Type) int64: 型のサイズを決定するためのカスタム関数。デフォルトの DefaultSizeof が存在しない場合に呼び出されます。
    • これらのフィールドが nil の場合、型チェッカーはデフォルトの計算ロジックを使用します。これにより、異なるプラットフォームや特定の要件を持つ環境(例: WebAssemblyターゲットなど)向けに、型チェッカーのサイズ計算動作を外部から注入・カスタマイズするメカニズムが提供されます。
  2. サイズ計算ロジックの sizes.go への集約:

    • src/pkg/go/types/sizes.go という新しいファイルが導入されました。以前は builtins.goexpr.go などに分散していた alignofsizeofDefaultAlignofDefaultSizeofalign などの関数がこのファイルに移動されました。
    • 特に、DefaultOffsetsof という新しい関数が sizes.go に追加され、構造体のフィールドオフセットのデフォルト計算ロジックがここにカプセル化されました。
    • この集約により、サイズ計算に関するすべてのロジックが一箇所にまとまり、コードの可読性、保守性、およびテスト容易性が大幅に向上しました。
  3. 構造体フィールドオフセットの内部表現の変更:

    • 以前は Field 構造体に Offset int64 フィールドがあり、構造体フィールドのオフセットが直接格納されていました。
    • このコミットでは、Field 構造体から Offset フィールドが削除され、Struct 構造体には offsets []int64 フィールドが追加されました(これは遅延評価されます)。
    • operand.golookupResult 構造体も offset int64 から index []int に変更されました。これは、埋め込みフィールドを持つ構造体の場合、フィールドへのアクセスパスが単一のオフセットではなく、複数のインデックスのシーケンスで表現されるようになったことを意味します。
    • 新しい Context.offsetof(typ Type, index []int) int64 関数が導入され、このインデックスシーケンスに基づいてフィールドの最終的なオフセットを計算します。これにより、埋め込みポインタを介したフィールドアクセスなど、より複雑なケースも正確に処理できるようになりました。
  4. 定数計算における整数型のサイズの正確な反映:

    • src/pkg/go/types/const.go において、isRepresentableConst および unaryOpConst 関数が *Context を引数として受け取るようになりました。
    • これにより、intuintuintptr などの整数型定数の表現可能性チェックや単項演算(例: ビット反転)において、Context.sizeof を通じて取得されるプラットフォーム固有の正確な型サイズが使用されるようになりました。以前は固定の intBitsptrBits が使われていましたが、これが動的に決定されるようになりました。これにより、異なるビット幅のシステムでの定数オーバーフロー検出の正確性が向上します。
  5. 文字列定数スライスのバグ修正 (Issue 4913):

    • src/pkg/go/types/expr.gorawExpr 関数内で、文字列定数をスライスした際の型推論に関するバグが修正されました。
    • 以前は、"foo"[1:2] のような文字列定数スライスが untyped string のままになることがありましたが、この修正により、結果の型が正しく string (typed string) に推論されるようになりました。これは、型なし定数から型付き定数への変換規則の厳密化と整合性を保つための変更です。
  6. GcImportContext 引数削除:

    • src/pkg/go/types/check.gosrc/pkg/go/types/gcimporter.go で、GcImport 関数が *Context 引数を受け取らなくなりました。これは、GcImport が型チェッカーのコンテキストに直接依存するのではなく、より独立したインポーターとして機能するように設計変更されたことを示唆しています。必要なコンテキスト情報は、Context 構造体の Import フィールドを通じて間接的に提供されるようになりました。

これらの変更は、Goの型チェッカーがより正確に、そして異なる実行環境に対してより柔軟に対応できるようにするための基盤を強化するものです。

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

このコミットにおけるコアとなるコードの変更箇所は以下の通りです。

  1. src/pkg/go/types/api.go:

    • Context 構造体に Offsetsof フィールドが追加され、AlignofSizeof のコメントが更新されました。
    --- a/src/pkg/go/types/api.go
    +++ b/src/pkg/go/types/api.go
    @@ -54,18 +54,21 @@ type Context struct {
     	// Otherwise, GcImporter is called.
     	Import Importer
     
    -	// If Alignof != nil, it is called to determine alignment.
    -	// Otherwise DefaultAlignmentof is called.
    -	// Alignof must return a size > 0, in bytes. It is not called
    -	// for arrays and structs (those alignments are based on the
    -	// alignment of the array elements or struct fields, respectively).\n
    +	// If Alignof != nil, it is called to determine the alignment
    +	// of the given type. Otherwise DefaultAlignmentof is called.
    +	// Alignof must implement the alignment guarantees required by
    +	// the spec.
     	Alignof func(Type) int64
     
    -	// If Sizeof != nil, it is called to determine sizes of types.
    -	// Otherwise, DefaultSizeof is called.
    -	// Sizeof must return a size >= 0, in bytes. It is not called
    -	// for arrays and structs (those sizes are based on the sizes
    -	// of the array elements or struct fields, respectively).\n
    +	// If Offsetsof != nil, it is called to determine the offsets
    +	// of the given struct fields, in bytes. Otherwise DefaultOffsetsof
    +	// is called. Offsetsof must implement the offset guarantees
    +	// required by the spec.
    +	Offsetsof func(fields []*Field) []int64
    +
    +	// If Sizeof != nil, it is called to determine the size of the
    +	// given type. Otherwise, DefaultSizeof is called. Sizeof must
    +	// implement the size guarantees required by the spec.
     	Sizeof func(Type) int64
     }
    
  2. src/pkg/go/types/sizes.go (新規ファイル):

    • サイズ、アライメント、オフセット計算のロジックがこの新しいファイルに集約されました。
    // Copyright 2013 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    // This file implements support for (unsafe) Alignof, Offsetof, and Sizeof.
    
    package types
    
    func (ctxt *Context) alignof(typ Type) int64 { ... }
    func (ctxt *Context) offsetsof(s *Struct) []int64 { ... }
    func (ctxt *Context) offsetof(typ Type, index []int) int64 { ... }
    func (ctxt *Context) sizeof(typ Type) int64 { ... }
    
    const DefaultMaxAlign = 8
    func DefaultAlignof(typ Type) int64 { ... }
    func align(x, a int64) int64 { ... }
    func DefaultOffsetsof(fields []*Field) []int64 { ... }
    
    const DefaultPtrSize = 8
    func DefaultSizeof(typ Type) int64 { ... }
    
  3. src/pkg/go/types/types.go:

    • Field 構造体から Offset フィールドが削除されました。
    • Struct 構造体から AlignmentSize フィールドが削除され、offsets []int64 が追加されました。
    --- a/src/pkg/go/types/types.go
    +++ b/src/pkg/go/types/types.go
    @@ -116,20 +116,18 @@ type Field struct {
     	QualifiedName
     	Type        Type
     	Tag         string
    -	Offset      int64 // offset within struct, in bytes
     	IsAnonymous bool
     }
     
     // A Struct represents a struct type struct{...}.
     type Struct struct {
    -	Fields    []*Field
    -	Alignment int64 // struct alignment in bytes
    -	Size      int64 // struct size in bytes
    +	Fields  []*Field
    +	offsets []int64 // field offsets in bytes, lazily computed
     }
     
    -func (typ *Struct) fieldIndex(name string) int {
    +func (typ *Struct) fieldIndex(name QualifiedName) int {
      	for i, f := range typ.Fields {
    -	\tif f.Name == name {
    +	\tif f.QualifiedName.IsSame(name) {
      		return i
      	}
      }
    
  4. src/pkg/go/types/operand.go:

    • lookupResult 構造体の offsetindex []int に変更されました。
    • embeddedTypeindex []int が追加されました。
    --- a/src/pkg/go/types/operand.go
    +++ b/src/pkg/go/types/operand.go
    @@ -129,7 +129,7 @@ func (x *operand) isNil() bool {
     //           overlapping in functionality. Need to simplify and clean up.
     
     // isAssignable reports whether x is assignable to a variable of type T.
    -func (x *operand) isAssignable(T Type) bool {
    +func (x *operand) isAssignable(ctxt *Context, T Type) bool {
      	if x.mode == invalid || T == Typ[Invalid] {
      		return true // avoid spurious errors
      	}
    @@ -187,7 +187,7 @@ func (x *operand) isAssignable(T Type) bool {
      	\tswitch t := Tu.(type) {
      	\tcase *Basic:
      	\t\tif x.mode == constant {
    -	\t\t\treturn isRepresentableConst(x.val, t.Kind)
    +	\t\t\treturn isRepresentableConst(x.val, ctxt, t.Kind)
      	\t\t}
      	\t\t// The result of a comparison is an untyped boolean,
      	\t\t// but may not be a constant.
    @@ -205,24 +205,23 @@ func (x *operand) isAssignable(T Type) bool {
     }
     
     // isInteger reports whether x is a (typed or untyped) integer value.
    -func (x *operand) isInteger() bool {
    +func (x *operand) isInteger(ctxt *Context) bool {
      	return x.mode == invalid ||
      	\tisInteger(x.typ) ||
    -	\tx.mode == constant && isRepresentableConst(x.val, UntypedInt)
    +	\tx.mode == constant && isRepresentableConst(x.val, ctxt, UntypedInt)
     }
     
     // lookupResult represents the result of a struct field/method lookup.
    -// TODO(gri) mode (variable for fields vs value for methods) and offset
    -//           (>= 0 vs <0) provide redundant data - simplify!
     type lookupResult struct {\n
    -	mode   operandMode
    -	typ    Type
    -	offset int64 // byte offset for struct fields, <0 for methods
    +	mode  operandMode
    +	typ   Type
    +	index []int // field index sequence; nil for methods
     }
     
     type embeddedType struct {\n
      	typ       *NamedType
    -	multiples bool // if set, typ is embedded multiple times at the same level
    +	index     []int // field index sequence
    +	multiples bool  // if set, typ is embedded multiple times at the same level
     }
    
  5. src/pkg/go/types/const.go:

    • isRepresentableConstunaryOpConst*Context を引数として受け取るようになり、サイズ計算に ctxt.sizeof を使用するようになりました。
    --- a/src/pkg/go/types/const.go
    +++ b/src/pkg/go/types/const.go
    @@ -206,7 +199,7 @@ func isNegConst(x interface{}) bool {
     // be represented as a value of the basic type Typ[as] without loss
     // of precision.
     //
    -func isRepresentableConst(x interface{}, as BasicKind) bool {
    +func isRepresentableConst(x interface{}, ctxt *Context, as BasicKind) bool {
      	switch x := x.(type) {
      	case bool:
      		return as == Bool || as == UntypedBool
    @@ -214,28 +207,33 @@ func isRepresentableConst(x interface{}, as BasicKind) bool {
      	case int64:
      		switch as {
      		case Int:
    -	\t\t\treturn -1<<(intBits-1) <= x && x <= 1<<(intBits-1)-1
    +	\t\t\tvar s = uint(ctxt.sizeof(Typ[as])) * 8
    +	\t\t\treturn int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
      		case Int8:
    -	\t\t\treturn -1<<(8-1) <= x && x <= 1<<(8-1)-1
    +	\t\t\tconst s = 8
    +	\t\t\treturn -1<<(s-1) <= x && x <= 1<<(s-1)-1
      		case Int16:
    -	\t\t\treturn -1<<(16-1) <= x && x <= 1<<(16-1)-1
    -	\t\tcase Int32, UntypedRune:
    -	\t\t\treturn -1<<(32-1) <= x && x <= 1<<(32-1)-1
    +	\t\t\tconst s = 16
    +	\t\t\treturn -1<<(s-1) <= x && x <= 1<<(s-1)-1
    +	\t\tcase Int32:
    +	\t\t\tconst s = 32
    +	\t\t\treturn -1<<(s-1) <= x && x <= 1<<(s-1)-1
      		case Int64:
      			return true
    -	\t\tcase Uint:
    -	\t\t\treturn 0 <= x && x <= 1<<intBits-1
    +	\t\tcase Uint, Uintptr:
    +	\t\t\tvar s = uint(ctxt.sizeof(Typ[as])) * 8
    +	\t\t\treturn 0 <= x && x <= int64(1)<<(s-1)-1
      		case Uint8:
    -	\t\t\treturn 0 <= x && x <= 1<<8-1
    +	\t\t\tconst s = 8
    +	\t\t\treturn 0 <= x && x <= 1<<s-1
      		case Uint16:
    -	\t\t\treturn 0 <= x && x <= 1<<16-1
    +	\t\t\tconst s = 16
    +	\t\t\treturn 0 <= x && x <= 1<<s-1
      		case Uint32:
    -	\t\t\treturn 0 <= x && x <= 1<<32-1
    +	\t\t\tconst s = 32
    +	\t\t\treturn 0 <= x && x <= 1<<s-1
      		case Uint64:
      			return 0 <= x
    -	\t\tcase Uintptr:
    -	\t\t\tassert(ptrBits == 64)
    -	\t\t\treturn 0 <= x
      		case Float32:
      			return true // TODO(gri) fix this
      		case Float64:
    @@ -250,12 +248,11 @@ func isRepresentableConst(x interface{}, as BasicKind) bool {
      
      	case *big.Int:
      		switch as {
    -	\t\tcase Uint:
    -	\t\t\treturn x.Sign() >= 0 && x.BitLen() <= intBits
    +	\t\tcase Uint, Uintptr:
    +	\t\t\tvar s = uint(ctxt.sizeof(Typ[as])) * 8
    +	\t\t\treturn x.Sign() >= 0 && x.BitLen() <= int(s)
      		case Uint64:
      			return x.Sign() >= 0 && x.BitLen() <= 64
    -	\t\tcase Uintptr:
    -	\t\t\treturn x.Sign() >= 0 && x.BitLen() <= ptrBits
      		case Float32:
      			return true // TODO(gri) fix this
      		case Float64:
    @@ -389,7 +386,7 @@ func is63bit(x int64) bool {
     }\n
     // unaryOpConst returns the result of the constant evaluation op x where x is of the given type.\n
    -func unaryOpConst(x interface{}, op token.Token, typ *Basic) interface{} {
    +func unaryOpConst(x interface{}, ctxt *Context, op token.Token, typ *Basic) interface{} {
      	switch op {
      	case token.ADD:
      		return x // nothing to do
    @@ -422,21 +419,8 @@ func unaryOpConst(x interface{}, op token.Token, typ *Basic) interface{} {
      	\t\t// thus "too large": We must limit the result size to
      	\t\t// the type's size.
      	\t\tif typ.Info&IsUnsigned != 0 {
    -	\t\t\ts := uint(typ.size) * 8
    -	\t\t\tif s == 0 {
    -	\t\t\t\t// platform-specific type
    -	\t\t\t\t// TODO(gri) this needs to be factored out
    -	\t\t\t\tswitch typ.Kind {
    -	\t\t\t\tcase Uint:
    -	\t\t\t\t\ts = intBits
    -	\t\t\t\tcase Uintptr:
    -	\t\t\t\t\ts = ptrBits
    -	\t\t\t\tdefault:
    -	\t\t\t\t\tunreachable()
    -	\t\t\t\t}
    -	\t\t\t}
    -	\t\t\t// z &^= (-1)<<s
    -	\t\t\tz.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s))
    +	\t\t\ts := uint(ctxt.sizeof(typ)) * 8
    +	\t\t\tz.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s)) // z &^= (-1)<<s
      	\t\t}
      	\t\treturn normalizeIntConst(&z)
      	\tcase token.NOT:
    

コアとなるコードの解説

このコミットの核心は、Goの型チェッカーが型サイズ、アライメント、構造体フィールドのオフセットを計算する方法を根本的に変更し、より柔軟でプラットフォームに依存しないようにした点にあります。

  1. Context を介したカスタマイズ性:

    • go/types パッケージの Context 構造体は、型チェックプロセス全体で共有される設定と状態を保持します。このコミットでは、AlignofOffsetsofSizeof という3つの関数型フィールドが Context に追加(または既存のものが強化)されました。
    • これにより、型チェッカーの利用者は、これらの関数を独自の実装で上書きすることで、特定のプラットフォーム(例: 32ビットARM、64ビットx86など)のメモリレイアウト規則に合わせて、型サイズやアライメントの計算ロジックをカスタマイズできるようになりました。これは、クロスコンパイルや特殊な実行環境(例: WebAssembly)をターゲットにする際に非常に重要です。
    • 例えば、Offsetsof[]*Field を受け取り、各フィールドのオフセットを示す []int64 を返します。これにより、構造体のパディングルールが異なる環境でも、正確なオフセットを型チェッカーに伝えることが可能になります。
  2. sizes.go によるロジックの集約とデフォルト実装:

    • sizes.go という新しいファイルは、unsafe パッケージの AlignofOffsetofSizeof に対応するデフォルトの計算ロジックをすべて含んでいます。
    • DefaultAlignofDefaultOffsetsofDefaultSizeof といった関数がここで定義されており、Context の対応するフィールドが nil の場合にフォールバックとして使用されます。
    • このファイルは、構造体のフィールドオフセットを計算するための align ヘルパー関数や、DefaultPtrSize (ポインタのデフォルトサイズ) などの定数も定義しています。
    • これにより、サイズ計算に関するすべてのロジックが論理的に一箇所にまとめられ、コードの整理と保守が容易になりました。
  3. 構造体フィールドオフセットの動的な計算と index パス:

    • 以前は Field 構造体に Offset が直接格納されていましたが、これは削除されました。代わりに、Struct 構造体には offsets []int64 が追加され、これは必要に応じて遅延計算されます。
    • operand.golookupResult 構造体も、フィールドのオフセットを直接持つのではなく、index []int というフィールドへのパスを持つようになりました。
    • これは、特に埋め込みフィールドを持つ構造体において、フィールドのオフセットが単一の数値ではなく、構造体の階層をたどるパスとして表現されるようになったことを意味します。例えば、Outer.Inner.Field のようなアクセスは、Outer 内の Inner のインデックスと、Inner 内の Field のインデックスのシーケンスとして表現されます。
    • 新しい Context.offsetof 関数は、この index パスと Context.offsetsof を利用して、最終的なフィールドのオフセットを動的に計算します。これにより、埋め込みポインタを介したフィールドアクセスなど、より複雑なケースでのオフセット計算の正確性が向上しました。
  4. 定数計算のプラットフォーム適応:

    • const.go で行われた変更は、定数式の評価において、intuintuintptr などの整数型のサイズが、もはや固定値(例: 32ビットまたは64ビット)ではなく、Context.sizeof を通じて取得されるプラットフォーム固有のサイズに基づいて決定されるようになったことを示しています。
    • これにより、異なるビット幅のシステムでコンパイルする際に、定数オーバーフローの検出がより正確になり、コンパイラが生成するコードの信頼性が向上します。

これらの変更は、Goの型チェッカーが、より多様なハードウェアアーキテクチャやオペレーティングシステムに対応し、unsafe 操作のセマンティクスをより正確にモデル化するための重要なステップです。

関連リンク

参考にした情報源リンク