Source file src/cmd/compile/internal/types2/gcsizes.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package types2
     6  
     7  type gcSizes struct {
     8  	WordSize int64 // word size in bytes - must be >= 4 (32bits)
     9  	MaxAlign int64 // maximum alignment in bytes - must be >= 1
    10  }
    11  
    12  func (s *gcSizes) Alignof(T Type) (result int64) {
    13  	defer func() {
    14  		assert(result >= 1)
    15  	}()
    16  
    17  	// For arrays and structs, alignment is defined in terms
    18  	// of alignment of the elements and fields, respectively.
    19  	switch t := under(T).(type) {
    20  	case *Array:
    21  		// spec: "For a variable x of array type: unsafe.Alignof(x)
    22  		// is the same as unsafe.Alignof(x[0]), but at least 1."
    23  		return s.Alignof(t.elem)
    24  	case *Struct:
    25  		if len(t.fields) == 0 && IsSyncAtomicAlign64(T) {
    26  			// Special case: sync/atomic.align64 is an
    27  			// empty struct we recognize as a signal that
    28  			// the struct it contains must be
    29  			// 64-bit-aligned.
    30  			//
    31  			// This logic is equivalent to the logic in
    32  			// cmd/compile/internal/types/size.go:calcStructOffset
    33  			return 8
    34  		}
    35  
    36  		// spec: "For a variable x of struct type: unsafe.Alignof(x)
    37  		// is the largest of the values unsafe.Alignof(x.f) for each
    38  		// field f of x, but at least 1."
    39  		max := int64(1)
    40  		for _, f := range t.fields {
    41  			if a := s.Alignof(f.typ); a > max {
    42  				max = a
    43  			}
    44  		}
    45  		return max
    46  	case *Slice, *Interface:
    47  		// Multiword data structures are effectively structs
    48  		// in which each element has size WordSize.
    49  		// Type parameters lead to variable sizes/alignments;
    50  		// StdSizes.Alignof won't be called for them.
    51  		assert(!isTypeParam(T))
    52  		return s.WordSize
    53  	case *Basic:
    54  		// Strings are like slices and interfaces.
    55  		if t.Info()&IsString != 0 {
    56  			return s.WordSize
    57  		}
    58  	case *TypeParam, *Union:
    59  		panic("unreachable")
    60  	}
    61  	a := s.Sizeof(T) // may be 0 or negative
    62  	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
    63  	if a < 1 {
    64  		return 1
    65  	}
    66  	// complex{64,128} are aligned like [2]float{32,64}.
    67  	if isComplex(T) {
    68  		a /= 2
    69  	}
    70  	if a > s.MaxAlign {
    71  		return s.MaxAlign
    72  	}
    73  	return a
    74  }
    75  
    76  func (s *gcSizes) Offsetsof(fields []*Var) []int64 {
    77  	offsets := make([]int64, len(fields))
    78  	var offs int64
    79  	for i, f := range fields {
    80  		if offs < 0 {
    81  			// all remaining offsets are too large
    82  			offsets[i] = -1
    83  			continue
    84  		}
    85  		// offs >= 0
    86  		a := s.Alignof(f.typ)
    87  		offs = align(offs, a) // possibly < 0 if align overflows
    88  		offsets[i] = offs
    89  		if d := s.Sizeof(f.typ); d >= 0 && offs >= 0 {
    90  			offs += d // ok to overflow to < 0
    91  		} else {
    92  			offs = -1 // f.typ or offs is too large
    93  		}
    94  	}
    95  	return offsets
    96  }
    97  
    98  func (s *gcSizes) Sizeof(T Type) int64 {
    99  	switch t := under(T).(type) {
   100  	case *Basic:
   101  		assert(isTyped(T))
   102  		k := t.kind
   103  		if int(k) < len(basicSizes) {
   104  			if s := basicSizes[k]; s > 0 {
   105  				return int64(s)
   106  			}
   107  		}
   108  		if k == String {
   109  			return s.WordSize * 2
   110  		}
   111  	case *Array:
   112  		n := t.len
   113  		if n <= 0 {
   114  			return 0
   115  		}
   116  		// n > 0
   117  		esize := s.Sizeof(t.elem)
   118  		if esize < 0 {
   119  			return -1 // element too large
   120  		}
   121  		if esize == 0 {
   122  			return 0 // 0-size element
   123  		}
   124  		// esize > 0
   125  		// Final size is esize * n; and size must be <= maxInt64.
   126  		const maxInt64 = 1<<63 - 1
   127  		if esize > maxInt64/n {
   128  			return -1 // esize * n overflows
   129  		}
   130  		return esize * n
   131  	case *Slice:
   132  		return s.WordSize * 3
   133  	case *Struct:
   134  		n := t.NumFields()
   135  		if n == 0 {
   136  			return 0
   137  		}
   138  		offsets := s.Offsetsof(t.fields)
   139  		offs := offsets[n-1]
   140  		size := s.Sizeof(t.fields[n-1].typ)
   141  		if offs < 0 || size < 0 {
   142  			return -1 // type too large
   143  		}
   144  		// gc: The last field of a non-zero-sized struct is not allowed to
   145  		// have size 0.
   146  		if offs > 0 && size == 0 {
   147  			size = 1
   148  		}
   149  		// gc: Size includes alignment padding.
   150  		return align(offs+size, s.Alignof(t)) // may overflow to < 0 which is ok
   151  	case *Interface:
   152  		// Type parameters lead to variable sizes/alignments;
   153  		// StdSizes.Sizeof won't be called for them.
   154  		assert(!isTypeParam(T))
   155  		return s.WordSize * 2
   156  	case *TypeParam, *Union:
   157  		panic("unreachable")
   158  	}
   159  	return s.WordSize // catch-all
   160  }
   161  
   162  // gcSizesFor returns the Sizes used by gc for an architecture.
   163  // The result is a nil *gcSizes pointer (which is not a valid types.Sizes)
   164  // if a compiler/architecture pair is not known.
   165  func gcSizesFor(compiler, arch string) *gcSizes {
   166  	if compiler != "gc" {
   167  		return nil
   168  	}
   169  	return gcArchSizes[arch]
   170  }
   171  

View as plain text