github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/cmd/compile/internal/gc/align.go (about)

     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 gc
     6  
     7  // machine size and rounding alignment is dictated around
     8  // the size of a pointer, set in betypeinit (see ../amd64/galign.go).
     9  var defercalc int
    10  
    11  func Rnd(o int64, r int64) int64 {
    12  	if r < 1 || r > 8 || r&(r-1) != 0 {
    13  		Fatalf("rnd %d", r)
    14  	}
    15  	return (o + r - 1) &^ (r - 1)
    16  }
    17  
    18  func offmod(t *Type) {
    19  	o := int32(0)
    20  	for _, f := range t.Fields().Slice() {
    21  		f.Offset = int64(o)
    22  		o += int32(Widthptr)
    23  		if int64(o) >= Thearch.MAXWIDTH {
    24  			yyerror("interface too large")
    25  			o = int32(Widthptr)
    26  		}
    27  	}
    28  }
    29  
    30  func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
    31  	starto := o
    32  	maxalign := int32(flag)
    33  	if maxalign < 1 {
    34  		maxalign = 1
    35  	}
    36  	lastzero := int64(0)
    37  	var w int64
    38  	for _, f := range t.Fields().Slice() {
    39  		if f.Type == nil {
    40  			// broken field, just skip it so that other valid fields
    41  			// get a width.
    42  			continue
    43  		}
    44  
    45  		dowidth(f.Type)
    46  		if int32(f.Type.Align) > maxalign {
    47  			maxalign = int32(f.Type.Align)
    48  		}
    49  		if f.Type.Width < 0 {
    50  			Fatalf("invalid width %d", f.Type.Width)
    51  		}
    52  		w = f.Type.Width
    53  		if f.Type.Align > 0 {
    54  			o = Rnd(o, int64(f.Type.Align))
    55  		}
    56  		f.Offset = o
    57  		if f.Nname != nil {
    58  			// addrescapes has similar code to update these offsets.
    59  			// Usually addrescapes runs after widstruct,
    60  			// in which case we could drop this,
    61  			// but function closure functions are the exception.
    62  			// NOTE(rsc): This comment may be stale.
    63  			// It's possible the ordering has changed and this is
    64  			// now the common case. I'm not sure.
    65  			if f.Nname.Name.Param.Stackcopy != nil {
    66  				f.Nname.Name.Param.Stackcopy.Xoffset = o
    67  				f.Nname.Xoffset = 0
    68  			} else {
    69  				f.Nname.Xoffset = o
    70  			}
    71  		}
    72  
    73  		if w == 0 {
    74  			lastzero = o
    75  		}
    76  		o += w
    77  		maxwidth := Thearch.MAXWIDTH
    78  		// On 32-bit systems, reflect tables impose an additional constraint
    79  		// that each field start offset must fit in 31 bits.
    80  		if maxwidth < 1<<32 {
    81  			maxwidth = 1<<31 - 1
    82  		}
    83  		if o >= maxwidth {
    84  			yyerror("type %L too large", errtype)
    85  			o = 8 // small but nonzero
    86  		}
    87  	}
    88  
    89  	// For nonzero-sized structs which end in a zero-sized thing, we add
    90  	// an extra byte of padding to the type. This padding ensures that
    91  	// taking the address of the zero-sized thing can't manufacture a
    92  	// pointer to the next object in the heap. See issue 9401.
    93  	if flag == 1 && o > starto && o == lastzero {
    94  		o++
    95  	}
    96  
    97  	// final width is rounded
    98  	if flag != 0 {
    99  		o = Rnd(o, int64(maxalign))
   100  	}
   101  	t.Align = uint8(maxalign)
   102  
   103  	// type width only includes back to first field's offset
   104  	t.Width = o - starto
   105  
   106  	return o
   107  }
   108  
   109  func dowidth(t *Type) {
   110  	if Widthptr == 0 {
   111  		Fatalf("dowidth without betypeinit")
   112  	}
   113  
   114  	if t == nil {
   115  		return
   116  	}
   117  
   118  	if t.Width > 0 {
   119  		if t.Align == 0 {
   120  			// See issue 11354
   121  			Fatalf("zero alignment with nonzero size %v", t)
   122  		}
   123  		return
   124  	}
   125  
   126  	if t.Width == -2 {
   127  		if !t.Broke {
   128  			t.Broke = true
   129  			yyerrorl(t.Pos, "invalid recursive type %v", t)
   130  		}
   131  
   132  		t.Width = 0
   133  		return
   134  	}
   135  
   136  	// break infinite recursion if the broken recursive type
   137  	// is referenced again
   138  	if t.Broke && t.Width == 0 {
   139  		return
   140  	}
   141  
   142  	// defer checkwidth calls until after we're done
   143  	defercalc++
   144  
   145  	lno := lineno
   146  	lineno = t.Pos
   147  	t.Width = -2
   148  	t.Align = 0
   149  
   150  	et := t.Etype
   151  	switch et {
   152  	case TFUNC, TCHAN, TMAP, TSTRING:
   153  		break
   154  
   155  	// simtype == 0 during bootstrap
   156  	default:
   157  		if simtype[t.Etype] != 0 {
   158  			et = simtype[t.Etype]
   159  		}
   160  	}
   161  
   162  	w := int64(0)
   163  	switch et {
   164  	default:
   165  		Fatalf("dowidth: unknown type: %v", t)
   166  
   167  	// compiler-specific stuff
   168  	case TINT8, TUINT8, TBOOL:
   169  		// bool is int8
   170  		w = 1
   171  
   172  	case TINT16, TUINT16:
   173  		w = 2
   174  
   175  	case TINT32, TUINT32, TFLOAT32:
   176  		w = 4
   177  
   178  	case TINT64, TUINT64, TFLOAT64:
   179  		w = 8
   180  		t.Align = uint8(Widthreg)
   181  
   182  	case TCOMPLEX64:
   183  		w = 8
   184  		t.Align = 4
   185  
   186  	case TCOMPLEX128:
   187  		w = 16
   188  		t.Align = uint8(Widthreg)
   189  
   190  	case TPTR32:
   191  		w = 4
   192  		checkwidth(t.Elem())
   193  
   194  	case TPTR64:
   195  		w = 8
   196  		checkwidth(t.Elem())
   197  
   198  	case TUNSAFEPTR:
   199  		w = int64(Widthptr)
   200  
   201  	case TINTER: // implemented as 2 pointers
   202  		w = 2 * int64(Widthptr)
   203  
   204  		t.Align = uint8(Widthptr)
   205  		offmod(t)
   206  
   207  	case TCHAN: // implemented as pointer
   208  		w = int64(Widthptr)
   209  
   210  		checkwidth(t.Elem())
   211  
   212  		// make fake type to check later to
   213  		// trigger channel argument check.
   214  		t1 := typChanArgs(t)
   215  		checkwidth(t1)
   216  
   217  	case TCHANARGS:
   218  		t1 := t.ChanArgs()
   219  		dowidth(t1) // just in case
   220  		if t1.Elem().Width >= 1<<16 {
   221  			yyerror("channel element type too large (>64kB)")
   222  		}
   223  		t.Width = 1
   224  
   225  	case TMAP: // implemented as pointer
   226  		w = int64(Widthptr)
   227  		checkwidth(t.Val())
   228  		checkwidth(t.Key())
   229  
   230  	case TFORW: // should have been filled in
   231  		if !t.Broke {
   232  			yyerror("invalid recursive type %v", t)
   233  		}
   234  		w = 1 // anything will do
   235  
   236  	case TANY:
   237  		// dummy type; should be replaced before use.
   238  		Fatalf("dowidth any")
   239  
   240  	case TSTRING:
   241  		if sizeof_String == 0 {
   242  			Fatalf("early dowidth string")
   243  		}
   244  		w = int64(sizeof_String)
   245  		t.Align = uint8(Widthptr)
   246  
   247  	case TARRAY:
   248  		if t.Elem() == nil {
   249  			break
   250  		}
   251  		if t.isDDDArray() {
   252  			if !t.Broke {
   253  				yyerror("use of [...] array outside of array literal")
   254  				t.Broke = true
   255  			}
   256  			break
   257  		}
   258  
   259  		dowidth(t.Elem())
   260  		if t.Elem().Width != 0 {
   261  			cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
   262  			if uint64(t.NumElem()) > cap {
   263  				yyerror("type %L larger than address space", t)
   264  			}
   265  		}
   266  		w = t.NumElem() * t.Elem().Width
   267  		t.Align = t.Elem().Align
   268  
   269  	case TSLICE:
   270  		if t.Elem() == nil {
   271  			break
   272  		}
   273  		w = int64(sizeof_Array)
   274  		checkwidth(t.Elem())
   275  		t.Align = uint8(Widthptr)
   276  
   277  	case TSTRUCT:
   278  		if t.IsFuncArgStruct() {
   279  			Fatalf("dowidth fn struct %v", t)
   280  		}
   281  		w = widstruct(t, t, 0, 1)
   282  
   283  	// make fake type to check later to
   284  	// trigger function argument computation.
   285  	case TFUNC:
   286  		t1 := typFuncArgs(t)
   287  		checkwidth(t1)
   288  		w = int64(Widthptr) // width of func type is pointer
   289  
   290  	// function is 3 cated structures;
   291  	// compute their widths as side-effect.
   292  	case TFUNCARGS:
   293  		t1 := t.FuncArgs()
   294  		w = widstruct(t1, t1.Recvs(), 0, 0)
   295  		w = widstruct(t1, t1.Params(), w, Widthreg)
   296  		w = widstruct(t1, t1.Results(), w, Widthreg)
   297  		t1.Extra.(*FuncType).Argwid = w
   298  		if w%int64(Widthreg) != 0 {
   299  			Warn("bad type %v %d\n", t1, w)
   300  		}
   301  		t.Align = 1
   302  	}
   303  
   304  	if Widthptr == 4 && w != int64(int32(w)) {
   305  		yyerror("type %v too large", t)
   306  	}
   307  
   308  	t.Width = w
   309  	if t.Align == 0 {
   310  		if w > 8 || w&(w-1) != 0 {
   311  			Fatalf("invalid alignment for %v", t)
   312  		}
   313  		t.Align = uint8(w)
   314  	}
   315  
   316  	lineno = lno
   317  
   318  	if defercalc == 1 {
   319  		resumecheckwidth()
   320  	} else {
   321  		defercalc--
   322  	}
   323  }
   324  
   325  // when a type's width should be known, we call checkwidth
   326  // to compute it.  during a declaration like
   327  //
   328  //	type T *struct { next T }
   329  //
   330  // it is necessary to defer the calculation of the struct width
   331  // until after T has been initialized to be a pointer to that struct.
   332  // similarly, during import processing structs may be used
   333  // before their definition.  in those situations, calling
   334  // defercheckwidth() stops width calculations until
   335  // resumecheckwidth() is called, at which point all the
   336  // checkwidths that were deferred are executed.
   337  // dowidth should only be called when the type's size
   338  // is needed immediately.  checkwidth makes sure the
   339  // size is evaluated eventually.
   340  
   341  var deferredTypeStack []*Type
   342  
   343  func checkwidth(t *Type) {
   344  	if t == nil {
   345  		return
   346  	}
   347  
   348  	// function arg structs should not be checked
   349  	// outside of the enclosing function.
   350  	if t.IsFuncArgStruct() {
   351  		Fatalf("checkwidth %v", t)
   352  	}
   353  
   354  	if defercalc == 0 {
   355  		dowidth(t)
   356  		return
   357  	}
   358  
   359  	if t.Deferwidth {
   360  		return
   361  	}
   362  	t.Deferwidth = true
   363  
   364  	deferredTypeStack = append(deferredTypeStack, t)
   365  }
   366  
   367  func defercheckwidth() {
   368  	// we get out of sync on syntax errors, so don't be pedantic.
   369  	if defercalc != 0 && nerrors == 0 {
   370  		Fatalf("defercheckwidth")
   371  	}
   372  	defercalc = 1
   373  }
   374  
   375  func resumecheckwidth() {
   376  	if defercalc == 0 {
   377  		Fatalf("resumecheckwidth")
   378  	}
   379  	for len(deferredTypeStack) > 0 {
   380  		t := deferredTypeStack[len(deferredTypeStack)-1]
   381  		deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
   382  		t.Deferwidth = false
   383  		dowidth(t)
   384  	}
   385  
   386  	defercalc = 0
   387  }