Source file src/cmd/compile/internal/types/size.go

     1  // Copyright 2009 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 types
     6  
     7  import (
     8  	"math"
     9  	"slices"
    10  
    11  	"cmd/compile/internal/base"
    12  	"cmd/internal/src"
    13  	"internal/buildcfg"
    14  	"internal/types/errors"
    15  )
    16  
    17  var PtrSize int
    18  
    19  var RegSize int
    20  
    21  // Slices in the runtime are represented by three components:
    22  //
    23  //	type slice struct {
    24  //		ptr unsafe.Pointer
    25  //		len int
    26  //		cap int
    27  //	}
    28  //
    29  // Strings in the runtime are represented by two components:
    30  //
    31  //	type string struct {
    32  //		ptr unsafe.Pointer
    33  //		len int
    34  //	}
    35  //
    36  // These variables are the offsets of fields and sizes of these structs.
    37  var (
    38  	SlicePtrOffset int64
    39  	SliceLenOffset int64
    40  	SliceCapOffset int64
    41  
    42  	SliceSize  int64
    43  	StringSize int64
    44  )
    45  
    46  var SkipSizeForTracing bool
    47  
    48  // typePos returns the position associated with t.
    49  // This is where t was declared or where it appeared as a type expression.
    50  func typePos(t *Type) src.XPos {
    51  	if pos := t.Pos(); pos.IsKnown() {
    52  		return pos
    53  	}
    54  	base.Fatalf("bad type: %v", t)
    55  	panic("unreachable")
    56  }
    57  
    58  // MaxWidth is the maximum size of a value on the target architecture.
    59  var MaxWidth int64
    60  
    61  // CalcSizeDisabled indicates whether it is safe
    62  // to calculate Types' widths and alignments. See CalcSize.
    63  var CalcSizeDisabled bool
    64  
    65  // machine size and rounding alignment is dictated around
    66  // the size of a pointer, set in gc.Main (see ../gc/main.go).
    67  var defercalc int
    68  
    69  // RoundUp rounds o to a multiple of r, r is a power of 2.
    70  func RoundUp(o int64, r int64) int64 {
    71  	if r < 1 || r > 8 || r&(r-1) != 0 {
    72  		base.Fatalf("Round %d", r)
    73  	}
    74  	return (o + r - 1) &^ (r - 1)
    75  }
    76  
    77  // expandiface computes the method set for interface type t by
    78  // expanding embedded interfaces.
    79  func expandiface(t *Type) {
    80  	seen := make(map[*Sym]*Field)
    81  	var methods []*Field
    82  
    83  	addMethod := func(m *Field, explicit bool) {
    84  		switch prev := seen[m.Sym]; {
    85  		case prev == nil:
    86  			seen[m.Sym] = m
    87  		case !explicit && Identical(m.Type, prev.Type):
    88  			return
    89  		default:
    90  			base.ErrorfAt(m.Pos, errors.DuplicateDecl, "duplicate method %s", m.Sym.Name)
    91  		}
    92  		methods = append(methods, m)
    93  	}
    94  
    95  	{
    96  		methods := t.Methods()
    97  		slices.SortStableFunc(methods, func(a, b *Field) int {
    98  			// Sort embedded types by type name (if any).
    99  			if a.Sym == nil && b.Sym == nil {
   100  				return CompareSyms(a.Type.Sym(), b.Type.Sym())
   101  			}
   102  
   103  			// Sort methods before embedded types.
   104  			if a.Sym == nil {
   105  				return -1
   106  			} else if b.Sym == nil {
   107  				return +1
   108  			}
   109  
   110  			// Sort methods by symbol name.
   111  			return CompareSyms(a.Sym, b.Sym)
   112  		})
   113  	}
   114  
   115  	for _, m := range t.Methods() {
   116  		if m.Sym == nil {
   117  			continue
   118  		}
   119  
   120  		CheckSize(m.Type)
   121  		addMethod(m, true)
   122  	}
   123  
   124  	for _, m := range t.Methods() {
   125  		if m.Sym != nil || m.Type == nil {
   126  			continue
   127  		}
   128  
   129  		// In 1.18, embedded types can be anything. In Go 1.17, we disallow
   130  		// embedding anything other than interfaces. This requirement was caught
   131  		// by types2 already, so allow non-interface here.
   132  		if !m.Type.IsInterface() {
   133  			continue
   134  		}
   135  
   136  		// Embedded interface: duplicate all methods
   137  		// and add to t's method set.
   138  		for _, t1 := range m.Type.AllMethods() {
   139  			f := NewField(m.Pos, t1.Sym, t1.Type)
   140  			addMethod(f, false)
   141  
   142  			// Clear position after typechecking, for consistency with types2.
   143  			f.Pos = src.NoXPos
   144  		}
   145  
   146  		// Clear position after typechecking, for consistency with types2.
   147  		m.Pos = src.NoXPos
   148  	}
   149  
   150  	slices.SortFunc(methods, CompareFields)
   151  
   152  	if int64(len(methods)) >= MaxWidth/int64(PtrSize) {
   153  		base.ErrorfAt(typePos(t), 0, "interface too large")
   154  	}
   155  	for i, m := range methods {
   156  		m.Offset = int64(i) * int64(PtrSize)
   157  	}
   158  
   159  	t.SetAllMethods(methods)
   160  }
   161  
   162  // calcStructOffset computes the offsets of a sequence of fields,
   163  // starting at the given offset. It returns the resulting offset and
   164  // maximum field alignment.
   165  func calcStructOffset(t *Type, fields []*Field, offset int64) int64 {
   166  	for _, f := range fields {
   167  		CalcSize(f.Type)
   168  		offset = RoundUp(offset, int64(f.Type.align))
   169  
   170  		if t.IsStruct() { // param offsets depend on ABI
   171  			f.Offset = offset
   172  
   173  			// If type T contains a field F marked as not-in-heap,
   174  			// then T must also be a not-in-heap type. Otherwise,
   175  			// you could heap allocate T and then get a pointer F,
   176  			// which would be a heap pointer to a not-in-heap type.
   177  			if f.Type.NotInHeap() {
   178  				t.SetNotInHeap(true)
   179  			}
   180  		}
   181  
   182  		offset += f.Type.width
   183  
   184  		maxwidth := MaxWidth
   185  		// On 32-bit systems, reflect tables impose an additional constraint
   186  		// that each field start offset must fit in 31 bits.
   187  		if maxwidth < 1<<32 {
   188  			maxwidth = 1<<31 - 1
   189  		}
   190  		if offset >= maxwidth {
   191  			base.ErrorfAt(typePos(t), 0, "type %L too large", t)
   192  			offset = 8 // small but nonzero
   193  		}
   194  	}
   195  
   196  	return offset
   197  }
   198  
   199  func isAtomicStdPkg(p *Pkg) bool {
   200  	if p.Prefix == `""` {
   201  		panic("bad package prefix")
   202  	}
   203  	return p.Prefix == "sync/atomic" || p.Prefix == "internal/runtime/atomic"
   204  }
   205  
   206  // CalcSize calculates and stores the size, alignment, eq/hash algorithm,
   207  // and ptrBytes for t.
   208  // If CalcSizeDisabled is set, and the size/alignment
   209  // have not already been calculated, it calls Fatal.
   210  // This is used to prevent data races in the back end.
   211  func CalcSize(t *Type) {
   212  	// Calling CalcSize when typecheck tracing enabled is not safe.
   213  	// See issue #33658.
   214  	if base.EnableTrace && SkipSizeForTracing {
   215  		return
   216  	}
   217  	if PtrSize == 0 {
   218  		// Assume this is a test.
   219  		return
   220  	}
   221  
   222  	if t == nil {
   223  		return
   224  	}
   225  
   226  	if t.width == -2 {
   227  		t.width = 0
   228  		t.align = 1
   229  		base.Fatalf("invalid recursive type %v", t)
   230  		return
   231  	}
   232  
   233  	if t.widthCalculated() {
   234  		return
   235  	}
   236  
   237  	if CalcSizeDisabled {
   238  		base.Fatalf("width not calculated: %v", t)
   239  	}
   240  
   241  	// defer CheckSize calls until after we're done
   242  	DeferCheckSize()
   243  
   244  	lno := base.Pos
   245  	if pos := t.Pos(); pos.IsKnown() {
   246  		base.Pos = pos
   247  	}
   248  
   249  	t.width = -2
   250  	t.align = 0  // 0 means use t.Width, below
   251  	t.alg = AMEM // default
   252  	// default t.ptrBytes is 0.
   253  	if t.Noalg() {
   254  		t.setAlg(ANOALG)
   255  	}
   256  
   257  	et := t.Kind()
   258  	switch et {
   259  	case TFUNC, TCHAN, TMAP, TSTRING:
   260  		break
   261  
   262  	// SimType == 0 during bootstrap
   263  	default:
   264  		if SimType[t.Kind()] != 0 {
   265  			et = SimType[t.Kind()]
   266  		}
   267  	}
   268  
   269  	var w int64
   270  	switch et {
   271  	default:
   272  		base.Fatalf("CalcSize: unknown type: %v", t)
   273  
   274  	// compiler-specific stuff
   275  	case TINT8, TUINT8, TBOOL:
   276  		// bool is int8
   277  		w = 1
   278  		t.intRegs = 1
   279  
   280  	case TINT16, TUINT16:
   281  		w = 2
   282  		t.intRegs = 1
   283  
   284  	case TINT32, TUINT32:
   285  		w = 4
   286  		t.intRegs = 1
   287  
   288  	case TINT64, TUINT64:
   289  		w = 8
   290  		t.align = uint8(RegSize)
   291  		t.intRegs = uint8(8 / RegSize)
   292  
   293  	case TFLOAT32:
   294  		w = 4
   295  		t.floatRegs = 1
   296  		t.setAlg(AFLOAT32)
   297  
   298  	case TFLOAT64:
   299  		w = 8
   300  		t.align = uint8(RegSize)
   301  		t.floatRegs = 1
   302  		t.setAlg(AFLOAT64)
   303  
   304  	case TCOMPLEX64:
   305  		w = 8
   306  		t.align = 4
   307  		t.floatRegs = 2
   308  		t.setAlg(ACPLX64)
   309  
   310  	case TCOMPLEX128:
   311  		w = 16
   312  		t.align = uint8(RegSize)
   313  		t.floatRegs = 2
   314  		t.setAlg(ACPLX128)
   315  
   316  	case TPTR:
   317  		w = int64(PtrSize)
   318  		t.intRegs = 1
   319  		CheckSize(t.Elem())
   320  		t.ptrBytes = int64(PtrSize) // See PtrDataSize
   321  
   322  	case TUNSAFEPTR:
   323  		w = int64(PtrSize)
   324  		t.intRegs = 1
   325  		t.ptrBytes = int64(PtrSize)
   326  
   327  	case TINTER: // implemented as 2 pointers
   328  		w = 2 * int64(PtrSize)
   329  		t.align = uint8(PtrSize)
   330  		t.intRegs = 2
   331  		expandiface(t)
   332  		if len(t.allMethods.Slice()) == 0 {
   333  			t.setAlg(ANILINTER)
   334  		} else {
   335  			t.setAlg(AINTER)
   336  		}
   337  		t.ptrBytes = int64(2 * PtrSize)
   338  
   339  	case TCHAN: // implemented as pointer
   340  		w = int64(PtrSize)
   341  		t.intRegs = 1
   342  		t.ptrBytes = int64(PtrSize)
   343  
   344  		CheckSize(t.Elem())
   345  
   346  		// Make fake type to trigger channel element size check after
   347  		// any top-level recursive type has been completed.
   348  		t1 := NewChanArgs(t)
   349  		CheckSize(t1)
   350  
   351  	case TCHANARGS:
   352  		t1 := t.ChanArgs()
   353  		CalcSize(t1) // just in case
   354  		// Make sure size of t1.Elem() is calculated at this point. We can
   355  		// use CalcSize() here rather than CheckSize(), because the top-level
   356  		// (possibly recursive) type will have been calculated before the fake
   357  		// chanargs is handled.
   358  		CalcSize(t1.Elem())
   359  		if t1.Elem().width >= 1<<16 {
   360  			base.Errorf("channel element type too large (>64kB)")
   361  		}
   362  		w = 1 // anything will do
   363  
   364  	case TMAP: // implemented as pointer
   365  		w = int64(PtrSize)
   366  		t.intRegs = 1
   367  		CheckSize(t.Elem())
   368  		CheckSize(t.Key())
   369  		t.setAlg(ANOEQ)
   370  		t.ptrBytes = int64(PtrSize)
   371  
   372  	case TFORW: // should have been filled in
   373  		base.Fatalf("invalid recursive type %v", t)
   374  
   375  	case TANY: // not a real type; should be replaced before use.
   376  		base.Fatalf("CalcSize any")
   377  
   378  	case TSTRING:
   379  		if StringSize == 0 {
   380  			base.Fatalf("early CalcSize string")
   381  		}
   382  		w = StringSize
   383  		t.align = uint8(PtrSize)
   384  		t.intRegs = 2
   385  		t.setAlg(ASTRING)
   386  		t.ptrBytes = int64(PtrSize)
   387  
   388  	case TARRAY:
   389  		if t.Elem() == nil {
   390  			break
   391  		}
   392  		CalcArraySize(t)
   393  		w = t.width
   394  
   395  	case TSLICE:
   396  		if t.Elem() == nil {
   397  			break
   398  		}
   399  		w = SliceSize
   400  		CheckSize(t.Elem())
   401  		t.align = uint8(PtrSize)
   402  		t.intRegs = 3
   403  		t.setAlg(ANOEQ)
   404  		if !t.Elem().NotInHeap() {
   405  			t.ptrBytes = int64(PtrSize)
   406  		}
   407  
   408  	case TSTRUCT:
   409  		if t.IsFuncArgStruct() {
   410  			base.Fatalf("CalcSize fn struct %v", t)
   411  		}
   412  		CalcStructSize(t)
   413  		w = t.width
   414  
   415  	// make fake type to check later to
   416  	// trigger function argument computation.
   417  	case TFUNC:
   418  		t1 := NewFuncArgs(t)
   419  		CheckSize(t1)
   420  		w = int64(PtrSize) // width of func type is pointer
   421  		t.intRegs = 1
   422  		t.setAlg(ANOEQ)
   423  		t.ptrBytes = int64(PtrSize)
   424  
   425  	// function is 3 cated structures;
   426  	// compute their widths as side-effect.
   427  	case TFUNCARGS:
   428  		t1 := t.FuncArgs()
   429  		// TODO(mdempsky): Should package abi be responsible for computing argwid?
   430  		w = calcStructOffset(t1, t1.Recvs(), 0)
   431  		w = calcStructOffset(t1, t1.Params(), w)
   432  		w = RoundUp(w, int64(RegSize))
   433  		w = calcStructOffset(t1, t1.Results(), w)
   434  		w = RoundUp(w, int64(RegSize))
   435  		t1.extra.(*Func).Argwid = w
   436  		t.align = 1
   437  	}
   438  
   439  	if PtrSize == 4 && w != int64(int32(w)) {
   440  		base.Errorf("type %v too large", t)
   441  	}
   442  
   443  	t.width = w
   444  	if t.align == 0 {
   445  		if w == 0 || w > 8 || w&(w-1) != 0 {
   446  			base.Fatalf("invalid alignment for %v", t)
   447  		}
   448  		t.align = uint8(w)
   449  	}
   450  
   451  	base.Pos = lno
   452  
   453  	ResumeCheckSize()
   454  }
   455  
   456  // simdify marks as type as "SIMD", either as a tag field,
   457  // or having the SIMD attribute.  The tag field is a marker
   458  // type used to identify a struct that is not really a struct.
   459  // A SIMD type is allocated to a vector register (on amd64,
   460  // xmm, ymm, or zmm).  The fields of a SIMD type are ignored
   461  // by the compiler except for the space that they reserve.
   462  func simdify(st *Type, isTag bool) {
   463  	st.align = 8
   464  	st.alg = ANOALG // not comparable with ==
   465  	st.intRegs = 0
   466  	st.isSIMD = true
   467  	if isTag {
   468  		st.width = 0
   469  		st.isSIMDTag = true
   470  		st.floatRegs = 0
   471  	} else {
   472  		st.floatRegs = 1
   473  	}
   474  }
   475  
   476  // CalcStructSize calculates the size of t,
   477  // filling in t.width, t.align, t.intRegs, and t.floatRegs,
   478  // even if size calculation is otherwise disabled.
   479  func CalcStructSize(t *Type) {
   480  	var maxAlign uint8 = 1
   481  
   482  	// Recognize special types. This logic is duplicated in go/types and
   483  	// cmd/compile/internal/types2.
   484  	if sym := t.Sym(); sym != nil {
   485  		switch {
   486  		case sym.Name == "align64" && isAtomicStdPkg(sym.Pkg):
   487  			maxAlign = 8
   488  
   489  		case buildcfg.Experiment.SIMD && (sym.Pkg.Path == "simd/archsimd") && len(t.Fields()) >= 1:
   490  			// This gates the experiment -- without it, no user-visible types can be "simd".
   491  			// The SSA-visible SIMD types remain.
   492  			switch sym.Name {
   493  			case "v128":
   494  				simdify(t, true)
   495  				return
   496  			case "v256":
   497  				simdify(t, true)
   498  				return
   499  			case "v512":
   500  				simdify(t, true)
   501  				return
   502  			}
   503  		}
   504  	}
   505  
   506  	fields := t.Fields()
   507  
   508  	size := calcStructOffset(t, fields, 0)
   509  
   510  	// For non-zero-sized structs which end in a zero-sized field, we
   511  	// add an extra byte of padding to the type. This padding ensures
   512  	// that taking the address of a zero-sized field can't manufacture a
   513  	// pointer to the next object in the heap. See issue 9401.
   514  	if size > 0 && fields[len(fields)-1].Type.width == 0 {
   515  		size++
   516  	}
   517  
   518  	var intRegs, floatRegs uint64
   519  	for _, field := range fields {
   520  		typ := field.Type
   521  
   522  		// The alignment of a struct type is the maximum alignment of its
   523  		// field types.
   524  		if align := typ.align; align > maxAlign {
   525  			maxAlign = align
   526  		}
   527  
   528  		// Each field needs its own registers.
   529  		// We sum in uint64 to avoid possible overflows.
   530  		intRegs += uint64(typ.intRegs)
   531  		floatRegs += uint64(typ.floatRegs)
   532  	}
   533  
   534  	// Final size includes trailing padding.
   535  	size = RoundUp(size, int64(maxAlign))
   536  
   537  	if intRegs > math.MaxUint8 || floatRegs > math.MaxUint8 {
   538  		intRegs = math.MaxUint8
   539  		floatRegs = math.MaxUint8
   540  	}
   541  
   542  	t.width = size
   543  	t.align = maxAlign
   544  	t.intRegs = uint8(intRegs)
   545  	t.floatRegs = uint8(floatRegs)
   546  
   547  	// Compute eq/hash algorithm type.
   548  	t.alg = AMEM // default
   549  	if t.Noalg() {
   550  		t.setAlg(ANOALG)
   551  	}
   552  	if len(fields) == 1 && !fields[0].Sym.IsBlank() {
   553  		// One-field struct is same as that one field alone.
   554  		t.setAlg(fields[0].Type.alg)
   555  	} else {
   556  		for i, f := range fields {
   557  			a := f.Type.alg
   558  			switch a {
   559  			case ANOEQ, ANOALG:
   560  			case AMEM:
   561  				// Blank fields and padded fields need a special compare.
   562  				if f.Sym.IsBlank() || IsPaddedField(t, i) {
   563  					a = ASPECIAL
   564  				}
   565  			default:
   566  				// Fields with non-memory equality need a special compare.
   567  				a = ASPECIAL
   568  			}
   569  			t.setAlg(a)
   570  		}
   571  	}
   572  	// Compute ptrBytes.
   573  	for i := len(fields) - 1; i >= 0; i-- {
   574  		f := fields[i]
   575  		if size := PtrDataSize(f.Type); size > 0 {
   576  			t.ptrBytes = f.Offset + size
   577  			break
   578  		}
   579  	}
   580  
   581  	if len(t.Fields()) >= 1 && t.Fields()[0].Type.isSIMDTag {
   582  		// this catches `type Foo simd.Whatever` -- Foo is also SIMD.
   583  		simdify(t, false)
   584  	}
   585  }
   586  
   587  // CalcArraySize calculates the size of t,
   588  // filling in t.width, t.align, t.alg, and t.ptrBytes,
   589  // even if size calculation is otherwise disabled.
   590  func CalcArraySize(t *Type) {
   591  	elem := t.Elem()
   592  	n := t.NumElem()
   593  	CalcSize(elem)
   594  	t.SetNotInHeap(elem.NotInHeap())
   595  	if elem.width != 0 {
   596  		cap := (uint64(MaxWidth) - 1) / uint64(elem.width)
   597  		if uint64(n) > cap {
   598  			base.Errorf("type %L larger than address space", t)
   599  		}
   600  	}
   601  
   602  	t.width = elem.width * n
   603  	t.align = elem.align
   604  	// ABIInternal only allows "trivial" arrays (i.e., length 0 or 1)
   605  	// to be passed by register.
   606  	switch n {
   607  	case 0:
   608  		t.intRegs = 0
   609  		t.floatRegs = 0
   610  	case 1:
   611  		t.intRegs = elem.intRegs
   612  		t.floatRegs = elem.floatRegs
   613  	default:
   614  		t.intRegs = math.MaxUint8
   615  		t.floatRegs = math.MaxUint8
   616  	}
   617  	t.alg = AMEM // default
   618  	if t.Noalg() {
   619  		t.setAlg(ANOALG)
   620  	}
   621  	switch a := elem.alg; a {
   622  	case AMEM, ANOEQ, ANOALG:
   623  		t.setAlg(a)
   624  	default:
   625  		switch n {
   626  		case 0:
   627  			// We checked above that the element type is comparable.
   628  			t.setAlg(AMEM)
   629  		case 1:
   630  			// Single-element array is same as its lone element.
   631  			t.setAlg(a)
   632  		default:
   633  			t.setAlg(ASPECIAL)
   634  		}
   635  	}
   636  	if n > 0 {
   637  		x := PtrDataSize(elem)
   638  		if x > 0 {
   639  			t.ptrBytes = elem.width*(n-1) + x
   640  		}
   641  	}
   642  }
   643  
   644  func (t *Type) widthCalculated() bool {
   645  	return t.align > 0
   646  }
   647  
   648  // when a type's width should be known, we call CheckSize
   649  // to compute it.  during a declaration like
   650  //
   651  //	type T *struct { next T }
   652  //
   653  // it is necessary to defer the calculation of the struct width
   654  // until after T has been initialized to be a pointer to that struct.
   655  // similarly, during import processing structs may be used
   656  // before their definition.  in those situations, calling
   657  // DeferCheckSize() stops width calculations until
   658  // ResumeCheckSize() is called, at which point all the
   659  // CalcSizes that were deferred are executed.
   660  // CalcSize should only be called when the type's size
   661  // is needed immediately.  CheckSize makes sure the
   662  // size is evaluated eventually.
   663  
   664  var deferredTypeStack []*Type
   665  
   666  func CheckSize(t *Type) {
   667  	if t == nil {
   668  		return
   669  	}
   670  
   671  	// function arg structs should not be checked
   672  	// outside of the enclosing function.
   673  	if t.IsFuncArgStruct() {
   674  		base.Fatalf("CheckSize %v", t)
   675  	}
   676  
   677  	if defercalc == 0 {
   678  		CalcSize(t)
   679  		return
   680  	}
   681  
   682  	// if type has not yet been pushed on deferredTypeStack yet, do it now
   683  	if !t.Deferwidth() {
   684  		t.SetDeferwidth(true)
   685  		deferredTypeStack = append(deferredTypeStack, t)
   686  	}
   687  }
   688  
   689  func DeferCheckSize() {
   690  	defercalc++
   691  }
   692  
   693  func ResumeCheckSize() {
   694  	if defercalc == 1 {
   695  		for len(deferredTypeStack) > 0 {
   696  			t := deferredTypeStack[len(deferredTypeStack)-1]
   697  			deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
   698  			t.SetDeferwidth(false)
   699  			CalcSize(t)
   700  		}
   701  	}
   702  
   703  	defercalc--
   704  }
   705  
   706  // PtrDataSize returns the length in bytes of the prefix of t
   707  // containing pointer data. Anything after this offset is scalar data.
   708  //
   709  // PtrDataSize is only defined for actual Go types. It's an error to
   710  // use it on compiler-internal types (e.g., TSSA, TRESULTS).
   711  func PtrDataSize(t *Type) int64 {
   712  	CalcSize(t)
   713  	x := t.ptrBytes
   714  	if t.Kind() == TPTR && t.Elem().NotInHeap() {
   715  		// Note: this is done here instead of when we're setting
   716  		// the ptrBytes field, because at that time (in NewPtr, usually)
   717  		// the NotInHeap bit of the element type might not be set yet.
   718  		x = 0
   719  	}
   720  	return x
   721  }
   722  

View as plain text