align.go 8.01 KB
Newer Older
1 2 3 4 5 6
// Copyright 2009 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.

package gc

7 8
// machine size and rounding alignment is dictated around
// the size of a pointer, set in betypeinit (see ../amd64/galign.go).
9 10 11 12
var defercalc int

func Rnd(o int64, r int64) int64 {
	if r < 1 || r > 8 || r&(r-1) != 0 {
13
		Fatalf("rnd %d", r)
14 15 16 17 18
	}
	return (o + r - 1) &^ (r - 1)
}

func offmod(t *Type) {
19
	o := int32(0)
20
	for _, f := range t.Fields().Slice() {
21 22 23 24 25 26 27 28 29 30
		f.Width = int64(o)
		o += int32(Widthptr)
		if int64(o) >= Thearch.MAXWIDTH {
			Yyerror("interface too large")
			o = int32(Widthptr)
		}
	}
}

func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
31 32
	starto := o
	maxalign := int32(flag)
33 34 35
	if maxalign < 1 {
		maxalign = 1
	}
36 37
	lastzero := int64(0)
	var w int64
38
	for _, f := range t.Fields().Slice() {
39 40 41 42 43 44 45 46 47 48 49
		if f.Type == nil {
			// broken field, just skip it so that other valid fields
			// get a width.
			continue
		}

		dowidth(f.Type)
		if int32(f.Type.Align) > maxalign {
			maxalign = int32(f.Type.Align)
		}
		if f.Type.Width < 0 {
50
			Fatalf("invalid width %d", f.Type.Width)
51 52 53 54 55 56 57 58
		}
		w = f.Type.Width
		if f.Type.Align > 0 {
			o = Rnd(o, int64(f.Type.Align))
		}
		f.Width = o // really offset for TFIELD
		if f.Nname != nil {
			// this same stackparam logic is in addrescapes
59
			// in typecheck.go.  usually addrescapes runs after
60 61
			// widstruct, in which case we could drop this,
			// but function closure functions are the exception.
62 63
			if f.Nname.Name.Param.Stackparam != nil {
				f.Nname.Name.Param.Stackparam.Xoffset = o
64 65 66 67 68 69 70 71 72 73 74
				f.Nname.Xoffset = 0
			} else {
				f.Nname.Xoffset = o
			}
		}

		if w == 0 {
			lastzero = o
		}
		o += w
		if o >= Thearch.MAXWIDTH {
75
			Yyerror("type %v too large", Tconv(errtype, FmtLong))
76 77 78 79 80
			o = 8 // small but nonzero
		}
	}

	// For nonzero-sized structs which end in a zero-sized thing, we add
81
	// an extra byte of padding to the type. This padding ensures that
82
	// taking the address of the zero-sized thing can't manufacture a
83
	// pointer to the next object in the heap. See issue 9401.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	if flag == 1 && o > starto && o == lastzero {
		o++
	}

	// final width is rounded
	if flag != 0 {
		o = Rnd(o, int64(maxalign))
	}
	t.Align = uint8(maxalign)

	// type width only includes back to first field's offset
	t.Width = o - starto

	return o
}

func dowidth(t *Type) {
	if Widthptr == 0 {
102
		Fatalf("dowidth without betypeinit")
103 104 105 106 107 108 109
	}

	if t == nil {
		return
	}

	if t.Width > 0 {
110 111
		if t.Align == 0 {
			// See issue 11354
112
			Fatalf("zero alignment with nonzero size %v", t)
113
		}
114 115 116 117
		return
	}

	if t.Width == -2 {
118 119
		if !t.Broke {
			t.Broke = true
120
			yyerrorl(t.Lineno, "invalid recursive type %v", t)
121 122 123 124 125 126 127 128
		}

		t.Width = 0
		return
	}

	// break infinite recursion if the broken recursive type
	// is referenced again
129
	if t.Broke && t.Width == 0 {
130 131 132 133 134 135
		return
	}

	// defer checkwidth calls until after we're done
	defercalc++

136
	lno := lineno
137
	lineno = t.Lineno
138 139 140
	t.Width = -2
	t.Align = 0

141
	et := t.Etype
142
	switch et {
143
	case TFUNC, TCHAN, TMAP, TSTRING:
144 145
		break

146
	// simtype == 0 during bootstrap
147 148
	default:
		if Simtype[t.Etype] != 0 {
149
			et = Simtype[t.Etype]
150 151 152
		}
	}

153
	w := int64(0)
154 155
	switch et {
	default:
156
		Fatalf("dowidth: unknown type: %v", t)
157

158
	// compiler-specific stuff
159
	case TINT8, TUINT8, TBOOL:
160 161 162
		// bool is int8
		w = 1

163
	case TINT16, TUINT16:
164 165
		w = 2

166
	case TINT32, TUINT32, TFLOAT32:
167 168
		w = 4

169
	case TINT64, TUINT64, TFLOAT64, TCOMPLEX64:
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
		w = 8
		t.Align = uint8(Widthreg)

	case TCOMPLEX128:
		w = 16
		t.Align = uint8(Widthreg)

	case TPTR32:
		w = 4
		checkwidth(t.Type)

	case TPTR64:
		w = 8
		checkwidth(t.Type)

	case TUNSAFEPTR:
		w = int64(Widthptr)

	case TINTER: // implemented as 2 pointers
		w = 2 * int64(Widthptr)

		t.Align = uint8(Widthptr)
		offmod(t)

	case TCHAN: // implemented as pointer
		w = int64(Widthptr)

		checkwidth(t.Type)

		// make fake type to check later to
		// trigger channel argument check.
201
		t1 := typ(TCHANARGS)
202 203 204 205 206

		t1.Type = t
		checkwidth(t1)

	case TCHANARGS:
207
		t1 := t.Type
208 209 210 211 212 213 214 215 216 217
		dowidth(t.Type) // just in case
		if t1.Type.Width >= 1<<16 {
			Yyerror("channel element type too large (>64kB)")
		}
		t.Width = 1

	case TMAP: // implemented as pointer
		w = int64(Widthptr)

		checkwidth(t.Type)
218
		checkwidth(t.Key())
219 220

	case TFORW: // should have been filled in
221
		if !t.Broke {
222
			Yyerror("invalid recursive type %v", t)
223 224 225
		}
		w = 1 // anything will do

226
	// dummy type; should be replaced before use.
227
	case TANY:
228
		if Debug['A'] == 0 {
229
			Fatalf("dowidth any")
230 231 232 233 234
		}
		w = 1 // anything will do

	case TSTRING:
		if sizeof_String == 0 {
235
			Fatalf("early dowidth string")
236 237 238 239 240 241 242 243 244 245 246
		}
		w = int64(sizeof_String)
		t.Align = uint8(Widthptr)

	case TARRAY:
		if t.Type == nil {
			break
		}
		if t.Bound >= 0 {
			dowidth(t.Type)
			if t.Type.Width != 0 {
247
				cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Type.Width)
248
				if uint64(t.Bound) > cap {
249
					Yyerror("type %v larger than address space", Tconv(t, FmtLong))
250 251 252 253 254 255 256 257 258 259
				}
			}

			w = t.Bound * t.Type.Width
			t.Align = t.Type.Align
		} else if t.Bound == -1 {
			w = int64(sizeof_Array)
			checkwidth(t.Type)
			t.Align = uint8(Widthptr)
		} else if t.Bound == -100 {
260
			if !t.Broke {
261
				Yyerror("use of [...] array outside of array literal")
262
				t.Broke = true
263 264
			}
		} else {
265
			Fatalf("dowidth %v", t) // probably [...]T
266 267 268
		}

	case TSTRUCT:
269
		if t.Funarg {
270
			Fatalf("dowidth fn struct %v", t)
271 272 273
		}
		w = widstruct(t, t, 0, 1)

274
	// make fake type to check later to
275 276
	// trigger function argument computation.
	case TFUNC:
277
		t1 := typ(TFUNCARGS)
278 279 280 281 282 283 284

		t1.Type = t
		checkwidth(t1)

		// width of func type is pointer
		w = int64(Widthptr)

285
	// function is 3 cated structures;
286 287
	// compute their widths as side-effect.
	case TFUNCARGS:
288
		t1 := t.Type
289

290
		w = widstruct(t.Type, t1.Recvs(), 0, 0)
291 292
		w = widstruct(t.Type, t1.Params(), w, Widthreg)
		w = widstruct(t.Type, t1.Results(), w, Widthreg)
293 294
		t1.Argwid = w
		if w%int64(Widthreg) != 0 {
295
			Warn("bad type %v %d\n", t1, w)
296 297 298 299 300
		}
		t.Align = 1
	}

	if Widthptr == 4 && w != int64(int32(w)) {
301
		Yyerror("type %v too large", t)
302 303 304 305 306
	}

	t.Width = w
	if t.Align == 0 {
		if w > 8 || w&(w-1) != 0 {
307
			Fatalf("invalid alignment for %v", t)
308 309 310 311
		}
		t.Align = uint8(w)
	}

312
	lineno = lno
313 314 315 316 317 318 319 320

	if defercalc == 1 {
		resumecheckwidth()
	} else {
		defercalc--
	}
}

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
// when a type's width should be known, we call checkwidth
// to compute it.  during a declaration like
//
//	type T *struct { next T }
//
// it is necessary to defer the calculation of the struct width
// until after T has been initialized to be a pointer to that struct.
// similarly, during import processing structs may be used
// before their definition.  in those situations, calling
// defercheckwidth() stops width calculations until
// resumecheckwidth() is called, at which point all the
// checkwidths that were deferred are executed.
// dowidth should only be called when the type's size
// is needed immediately.  checkwidth makes sure the
// size is evaluated eventually.
336

337
var deferredTypeStack []*Type
338 339 340 341 342 343 344 345

func checkwidth(t *Type) {
	if t == nil {
		return
	}

	// function arg structs should not be checked
	// outside of the enclosing function.
346
	if t.Funarg {
347
		Fatalf("checkwidth %v", t)
348 349
	}

350
	if defercalc == 0 {
351 352 353 354
		dowidth(t)
		return
	}

355
	if t.Deferwidth {
356 357
		return
	}
358
	t.Deferwidth = true
359

360
	deferredTypeStack = append(deferredTypeStack, t)
361 362 363 364 365
}

func defercheckwidth() {
	// we get out of sync on syntax errors, so don't be pedantic.
	if defercalc != 0 && nerrors == 0 {
366
		Fatalf("defercheckwidth")
367 368 369 370 371
	}
	defercalc = 1
}

func resumecheckwidth() {
372
	if defercalc == 0 {
373
		Fatalf("resumecheckwidth")
374
	}
375 376 377 378 379
	for len(deferredTypeStack) > 0 {
		t := deferredTypeStack[len(deferredTypeStack)-1]
		deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
		t.Deferwidth = false
		dowidth(t)
380 381 382 383 384
	}

	defercalc = 0
}

385
// compute total size of f's in/out arguments.
386
func Argsize(t *Type) int {
387
	var w int64
388

389
	for _, p := range recvsParamsResults {
390
		for _, f := range p(t).Fields().Slice() {
391 392 393
			if x := f.Width + f.Type.Width; x > w {
				w = x
			}
394 395 396 397 398
		}
	}

	w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
	if int64(int(w)) != w {
399
		Fatalf("argsize too big")
400 401 402
	}
	return int(w)
}