2015-02-13 14:40:36 -05:00
|
|
|
// 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
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// machine size and rounding alignment is dictated around
|
|
|
|
|
// the size of a pointer, set in betypeinit (see ../amd64/galign.go).
|
2015-02-13 14:40:36 -05:00
|
|
|
var defercalc int
|
|
|
|
|
|
|
|
|
|
func Rnd(o int64, r int64) int64 {
|
|
|
|
|
if r < 1 || r > 8 || r&(r-1) != 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("rnd %d", r)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return (o + r - 1) &^ (r - 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func offmod(t *Type) {
|
2015-02-23 16:07:24 -05:00
|
|
|
o := int32(0)
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range t.Fields().Slice() {
|
2016-03-28 09:40:53 -07:00
|
|
|
f.Offset = int64(o)
|
2015-02-13 14:40:36 -05:00
|
|
|
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 {
|
2015-02-23 16:07:24 -05:00
|
|
|
starto := o
|
|
|
|
|
maxalign := int32(flag)
|
2015-02-13 14:40:36 -05:00
|
|
|
if maxalign < 1 {
|
|
|
|
|
maxalign = 1
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
lastzero := int64(0)
|
|
|
|
|
var w int64
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range t.Fields().Slice() {
|
2015-02-13 14:40:36 -05:00
|
|
|
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 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("invalid width %d", f.Type.Width)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
w = f.Type.Width
|
|
|
|
|
if f.Type.Align > 0 {
|
|
|
|
|
o = Rnd(o, int64(f.Type.Align))
|
|
|
|
|
}
|
2016-03-28 09:40:53 -07:00
|
|
|
f.Offset = o
|
2015-02-13 14:40:36 -05:00
|
|
|
if f.Nname != nil {
|
|
|
|
|
// this same stackparam logic is in addrescapes
|
2015-10-22 09:51:12 +09:00
|
|
|
// in typecheck.go. usually addrescapes runs after
|
2015-02-13 14:40:36 -05:00
|
|
|
// widstruct, in which case we could drop this,
|
|
|
|
|
// but function closure functions are the exception.
|
2015-05-27 00:44:05 -04:00
|
|
|
if f.Nname.Name.Param.Stackparam != nil {
|
|
|
|
|
f.Nname.Name.Param.Stackparam.Xoffset = o
|
2015-02-13 14:40:36 -05:00
|
|
|
f.Nname.Xoffset = 0
|
|
|
|
|
} else {
|
|
|
|
|
f.Nname.Xoffset = o
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if w == 0 {
|
|
|
|
|
lastzero = o
|
|
|
|
|
}
|
|
|
|
|
o += w
|
|
|
|
|
if o >= Thearch.MAXWIDTH {
|
2016-03-15 13:06:58 -07:00
|
|
|
Yyerror("type %v too large", Tconv(errtype, FmtLong))
|
2015-02-13 14:40:36 -05:00
|
|
|
o = 8 // small but nonzero
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For nonzero-sized structs which end in a zero-sized thing, we add
|
2016-03-01 23:21:55 +00:00
|
|
|
// an extra byte of padding to the type. This padding ensures that
|
2015-02-13 14:40:36 -05:00
|
|
|
// taking the address of the zero-sized thing can't manufacture a
|
2016-03-01 23:21:55 +00:00
|
|
|
// pointer to the next object in the heap. See issue 9401.
|
2015-02-13 14:40:36 -05:00
|
|
|
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 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("dowidth without betypeinit")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Width > 0 {
|
2015-06-24 07:23:40 -07:00
|
|
|
if t.Align == 0 {
|
|
|
|
|
// See issue 11354
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("zero alignment with nonzero size %v", t)
|
2015-06-24 07:23:40 -07:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Width == -2 {
|
2015-09-07 10:37:26 +10:00
|
|
|
if !t.Broke {
|
|
|
|
|
t.Broke = true
|
2016-03-02 20:32:40 -08:00
|
|
|
yyerrorl(t.Lineno, "invalid recursive type %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Width = 0
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// break infinite recursion if the broken recursive type
|
|
|
|
|
// is referenced again
|
2015-09-07 10:37:26 +10:00
|
|
|
if t.Broke && t.Width == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// defer checkwidth calls until after we're done
|
|
|
|
|
defercalc++
|
|
|
|
|
|
2016-03-02 17:34:42 -08:00
|
|
|
lno := lineno
|
2016-03-02 20:32:40 -08:00
|
|
|
lineno = t.Lineno
|
2015-02-13 14:40:36 -05:00
|
|
|
t.Width = -2
|
|
|
|
|
t.Align = 0
|
|
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
et := t.Etype
|
2015-02-13 14:40:36 -05:00
|
|
|
switch et {
|
2015-04-01 09:38:44 -07:00
|
|
|
case TFUNC, TCHAN, TMAP, TSTRING:
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// simtype == 0 during bootstrap
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
|
|
|
|
if Simtype[t.Etype] != 0 {
|
2015-09-24 23:21:18 +02:00
|
|
|
et = Simtype[t.Etype]
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
w := int64(0)
|
2015-02-13 14:40:36 -05:00
|
|
|
switch et {
|
|
|
|
|
default:
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("dowidth: unknown type: %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// compiler-specific stuff
|
2015-04-01 09:38:44 -07:00
|
|
|
case TINT8, TUINT8, TBOOL:
|
2015-02-13 14:40:36 -05:00
|
|
|
// bool is int8
|
|
|
|
|
w = 1
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case TINT16, TUINT16:
|
2015-02-13 14:40:36 -05:00
|
|
|
w = 2
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case TINT32, TUINT32, TFLOAT32:
|
2015-02-13 14:40:36 -05:00
|
|
|
w = 4
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case TINT64, TUINT64, TFLOAT64, TCOMPLEX64:
|
2015-02-13 14:40:36 -05:00
|
|
|
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.
|
2015-02-23 16:07:24 -05:00
|
|
|
t1 := typ(TCHANARGS)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
t1.Type = t
|
|
|
|
|
checkwidth(t1)
|
|
|
|
|
|
|
|
|
|
case TCHANARGS:
|
2015-02-23 16:07:24 -05:00
|
|
|
t1 := t.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
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)
|
2016-03-10 05:22:14 -08:00
|
|
|
checkwidth(t.Key())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TFORW: // should have been filled in
|
2015-09-07 10:37:26 +10:00
|
|
|
if !t.Broke {
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("invalid recursive type %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
w = 1 // anything will do
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// dummy type; should be replaced before use.
|
2015-02-13 14:40:36 -05:00
|
|
|
case TANY:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Debug['A'] == 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("dowidth any")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
w = 1 // anything will do
|
|
|
|
|
|
|
|
|
|
case TSTRING:
|
|
|
|
|
if sizeof_String == 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("early dowidth string")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
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 {
|
2015-02-23 16:07:24 -05:00
|
|
|
cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Type.Width)
|
2015-02-13 14:40:36 -05:00
|
|
|
if uint64(t.Bound) > cap {
|
2016-03-15 13:06:58 -07:00
|
|
|
Yyerror("type %v larger than address space", Tconv(t, FmtLong))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
2016-03-27 17:57:42 -07:00
|
|
|
} else if t.isDDDArray() {
|
2015-09-07 10:37:26 +10:00
|
|
|
if !t.Broke {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("use of [...] array outside of array literal")
|
2015-09-07 10:37:26 +10:00
|
|
|
t.Broke = true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
} else {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("dowidth %v", t) // probably [...]T
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSTRUCT:
|
2015-09-08 03:51:30 +02:00
|
|
|
if t.Funarg {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("dowidth fn struct %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
w = widstruct(t, t, 0, 1)
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// make fake type to check later to
|
2015-02-13 14:40:36 -05:00
|
|
|
// trigger function argument computation.
|
|
|
|
|
case TFUNC:
|
2015-02-23 16:07:24 -05:00
|
|
|
t1 := typ(TFUNCARGS)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
t1.Type = t
|
|
|
|
|
checkwidth(t1)
|
|
|
|
|
|
|
|
|
|
// width of func type is pointer
|
|
|
|
|
w = int64(Widthptr)
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// function is 3 cated structures;
|
2015-02-13 14:40:36 -05:00
|
|
|
// compute their widths as side-effect.
|
|
|
|
|
case TFUNCARGS:
|
2015-02-23 16:07:24 -05:00
|
|
|
t1 := t.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-09 20:54:59 -08:00
|
|
|
w = widstruct(t.Type, t1.Recvs(), 0, 0)
|
2016-03-08 16:31:28 -08:00
|
|
|
w = widstruct(t.Type, t1.Params(), w, Widthreg)
|
|
|
|
|
w = widstruct(t.Type, t1.Results(), w, Widthreg)
|
2015-02-13 14:40:36 -05:00
|
|
|
t1.Argwid = w
|
|
|
|
|
if w%int64(Widthreg) != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
Warn("bad type %v %d\n", t1, w)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
t.Align = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Widthptr == 4 && w != int64(int32(w)) {
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("type %v too large", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Width = w
|
|
|
|
|
if t.Align == 0 {
|
|
|
|
|
if w > 8 || w&(w-1) != 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("invalid alignment for %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
t.Align = uint8(w)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-02 17:34:42 -08:00
|
|
|
lineno = lno
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if defercalc == 1 {
|
|
|
|
|
resumecheckwidth()
|
|
|
|
|
} else {
|
|
|
|
|
defercalc--
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// 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.
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-04 01:30:31 -08:00
|
|
|
var deferredTypeStack []*Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
func checkwidth(t *Type) {
|
|
|
|
|
if t == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// function arg structs should not be checked
|
|
|
|
|
// outside of the enclosing function.
|
2015-09-08 03:51:30 +02:00
|
|
|
if t.Funarg {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("checkwidth %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if defercalc == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
dowidth(t)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-08 03:51:30 +02:00
|
|
|
if t.Deferwidth {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
2015-09-08 03:51:30 +02:00
|
|
|
t.Deferwidth = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-04 01:30:31 -08:00
|
|
|
deferredTypeStack = append(deferredTypeStack, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func defercheckwidth() {
|
|
|
|
|
// we get out of sync on syntax errors, so don't be pedantic.
|
|
|
|
|
if defercalc != 0 && nerrors == 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("defercheckwidth")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
defercalc = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func resumecheckwidth() {
|
2015-02-17 22:13:49 -05:00
|
|
|
if defercalc == 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("resumecheckwidth")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-04 01:30:31 -08:00
|
|
|
for len(deferredTypeStack) > 0 {
|
|
|
|
|
t := deferredTypeStack[len(deferredTypeStack)-1]
|
|
|
|
|
deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
|
|
|
|
|
t.Deferwidth = false
|
|
|
|
|
dowidth(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
defercalc = 0
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// compute total size of f's in/out arguments.
|
2015-02-13 14:40:36 -05:00
|
|
|
func Argsize(t *Type) int {
|
2016-03-08 15:02:40 -08:00
|
|
|
var w int64
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-09 20:54:59 -08:00
|
|
|
for _, p := range recvsParamsResults {
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range p(t).Fields().Slice() {
|
2016-03-28 10:35:13 -07:00
|
|
|
if x := f.End(); x > w {
|
2016-03-08 17:45:55 -08:00
|
|
|
w = x
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
|
|
|
|
|
if int64(int(w)) != w {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("argsize too big")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return int(w)
|
|
|
|
|
}
|