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