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 5package types 6 7import ( 8 "bytes" 9 "fmt" 10 "sort" 11 12 "cmd/compile/internal/base" 13 "cmd/internal/src" 14) 15 16var PtrSize int 17 18var RegSize int 19 20// Slices in the runtime are represented by three components: 21// 22// type slice struct { 23// ptr unsafe.Pointer 24// len int 25// cap int 26// } 27// 28// Strings in the runtime are represented by two components: 29// 30// type string struct { 31// ptr unsafe.Pointer 32// len int 33// } 34// 35// These variables are the offsets of fields and sizes of these structs. 36var ( 37 SlicePtrOffset int64 38 SliceLenOffset int64 39 SliceCapOffset int64 40 41 SliceSize int64 42 StringSize int64 43) 44 45var SkipSizeForTracing bool 46 47// typePos returns the position associated with t. 48// This is where t was declared or where it appeared as a type expression. 49func typePos(t *Type) src.XPos { 50 if pos := t.Pos(); pos.IsKnown() { 51 return pos 52 } 53 base.Fatalf("bad type: %v", t) 54 panic("unreachable") 55} 56 57// MaxWidth is the maximum size of a value on the target architecture. 58var MaxWidth int64 59 60// CalcSizeDisabled indicates whether it is safe 61// to calculate Types' widths and alignments. See CalcSize. 62var CalcSizeDisabled bool 63 64// machine size and rounding alignment is dictated around 65// the size of a pointer, set in betypeinit (see ../amd64/galign.go). 66var defercalc int 67 68func Rnd(o int64, r int64) int64 { 69 if r < 1 || r > 8 || r&(r-1) != 0 { 70 base.Fatalf("rnd %d", r) 71 } 72 return (o + r - 1) &^ (r - 1) 73} 74 75// expandiface computes the method set for interface type t by 76// expanding embedded interfaces. 77func expandiface(t *Type) { 78 seen := make(map[*Sym]*Field) 79 var methods []*Field 80 81 addMethod := func(m *Field, explicit bool) { 82 switch prev := seen[m.Sym]; { 83 case prev == nil: 84 seen[m.Sym] = m 85 case AllowsGoVersion(t.Pkg(), 1, 14) && !explicit && Identical(m.Type, prev.Type): 86 return 87 default: 88 base.ErrorfAt(m.Pos, "duplicate method %s", m.Sym.Name) 89 } 90 methods = append(methods, m) 91 } 92 93 { 94 methods := t.Methods().Slice() 95 sort.SliceStable(methods, func(i, j int) bool { 96 mi, mj := methods[i], methods[j] 97 98 // Sort embedded types by type name (if any). 99 if mi.Sym == nil && mj.Sym == nil { 100 return mi.Type.Sym().Less(mj.Type.Sym()) 101 } 102 103 // Sort methods before embedded types. 104 if mi.Sym == nil || mj.Sym == nil { 105 return mi.Sym != nil 106 } 107 108 // Sort methods by symbol name. 109 return mi.Sym.Less(mj.Sym) 110 }) 111 } 112 113 for _, m := range t.Methods().Slice() { 114 if m.Sym == nil { 115 continue 116 } 117 118 CheckSize(m.Type) 119 addMethod(m, true) 120 } 121 122 for _, m := range t.Methods().Slice() { 123 if m.Sym != nil || m.Type == nil { 124 continue 125 } 126 127 if m.Type.IsUnion() { 128 continue 129 } 130 131 // In 1.18, embedded types can be anything. In Go 1.17, we disallow 132 // embedding anything other than interfaces. 133 if !m.Type.IsInterface() { 134 if AllowsGoVersion(t.Pkg(), 1, 18) { 135 continue 136 } 137 base.ErrorfAt(m.Pos, "interface contains embedded non-interface, non-union %v", m.Type) 138 m.SetBroke(true) 139 t.SetBroke(true) 140 // Add to fields so that error messages 141 // include the broken embedded type when 142 // printing t. 143 // TODO(mdempsky): Revisit this. 144 methods = append(methods, m) 145 continue 146 } 147 148 // Embedded interface: duplicate all methods 149 // (including broken ones, if any) and add to t's 150 // method set. 151 for _, t1 := range m.Type.AllMethods().Slice() { 152 f := NewField(m.Pos, t1.Sym, t1.Type) 153 addMethod(f, false) 154 155 // Clear position after typechecking, for consistency with types2. 156 f.Pos = src.NoXPos 157 } 158 159 // Clear position after typechecking, for consistency with types2. 160 m.Pos = src.NoXPos 161 } 162 163 sort.Sort(MethodsByName(methods)) 164 165 if int64(len(methods)) >= MaxWidth/int64(PtrSize) { 166 base.ErrorfAt(typePos(t), "interface too large") 167 } 168 for i, m := range methods { 169 m.Offset = int64(i) * int64(PtrSize) 170 } 171 172 t.SetAllMethods(methods) 173} 174 175func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 { 176 // flag is 0 (receiver), 1 (actual struct), or RegSize (in/out parameters) 177 isStruct := flag == 1 178 starto := o 179 maxalign := int32(flag) 180 if maxalign < 1 { 181 maxalign = 1 182 } 183 lastzero := int64(0) 184 for _, f := range t.Fields().Slice() { 185 if f.Type == nil { 186 // broken field, just skip it so that other valid fields 187 // get a width. 188 continue 189 } 190 191 CalcSize(f.Type) 192 if int32(f.Type.align) > maxalign { 193 maxalign = int32(f.Type.align) 194 } 195 if f.Type.align > 0 { 196 o = Rnd(o, int64(f.Type.align)) 197 } 198 if isStruct { // For receiver/args/results, do not set, it depends on ABI 199 f.Offset = o 200 } 201 202 w := f.Type.width 203 if w < 0 { 204 base.Fatalf("invalid width %d", f.Type.width) 205 } 206 if w == 0 { 207 lastzero = o 208 } 209 o += w 210 maxwidth := MaxWidth 211 // On 32-bit systems, reflect tables impose an additional constraint 212 // that each field start offset must fit in 31 bits. 213 if maxwidth < 1<<32 { 214 maxwidth = 1<<31 - 1 215 } 216 if o >= maxwidth { 217 base.ErrorfAt(typePos(errtype), "type %L too large", errtype) 218 o = 8 // small but nonzero 219 } 220 } 221 222 // For nonzero-sized structs which end in a zero-sized thing, we add 223 // an extra byte of padding to the type. This padding ensures that 224 // taking the address of the zero-sized thing can't manufacture a 225 // pointer to the next object in the heap. See issue 9401. 226 if flag == 1 && o > starto && o == lastzero { 227 o++ 228 } 229 230 // final width is rounded 231 if flag != 0 { 232 o = Rnd(o, int64(maxalign)) 233 } 234 t.align = uint8(maxalign) 235 236 // type width only includes back to first field's offset 237 t.width = o - starto 238 239 return o 240} 241 242// findTypeLoop searches for an invalid type declaration loop involving 243// type t and reports whether one is found. If so, path contains the 244// loop. 245// 246// path points to a slice used for tracking the sequence of types 247// visited. Using a pointer to a slice allows the slice capacity to 248// grow and limit reallocations. 249func findTypeLoop(t *Type, path *[]*Type) bool { 250 // We implement a simple DFS loop-finding algorithm. This 251 // could be faster, but type cycles are rare. 252 253 if t.Sym() != nil { 254 // Declared type. Check for loops and otherwise 255 // recurse on the type expression used in the type 256 // declaration. 257 258 // Type imported from package, so it can't be part of 259 // a type loop (otherwise that package should have 260 // failed to compile). 261 if t.Sym().Pkg != LocalPkg { 262 return false 263 } 264 265 for i, x := range *path { 266 if x == t { 267 *path = (*path)[i:] 268 return true 269 } 270 } 271 272 *path = append(*path, t) 273 if findTypeLoop(t.Obj().(TypeObject).TypeDefn(), path) { 274 return true 275 } 276 *path = (*path)[:len(*path)-1] 277 } else { 278 // Anonymous type. Recurse on contained types. 279 280 switch t.Kind() { 281 case TARRAY: 282 if findTypeLoop(t.Elem(), path) { 283 return true 284 } 285 case TSTRUCT: 286 for _, f := range t.Fields().Slice() { 287 if findTypeLoop(f.Type, path) { 288 return true 289 } 290 } 291 case TINTER: 292 for _, m := range t.Methods().Slice() { 293 if m.Type.IsInterface() { // embedded interface 294 if findTypeLoop(m.Type, path) { 295 return true 296 } 297 } 298 } 299 } 300 } 301 302 return false 303} 304 305func reportTypeLoop(t *Type) { 306 if t.Broke() { 307 return 308 } 309 310 var l []*Type 311 if !findTypeLoop(t, &l) { 312 base.Fatalf("failed to find type loop for: %v", t) 313 } 314 315 // Rotate loop so that the earliest type declaration is first. 316 i := 0 317 for j, t := range l[1:] { 318 if typePos(t).Before(typePos(l[i])) { 319 i = j + 1 320 } 321 } 322 l = append(l[i:], l[:i]...) 323 324 var msg bytes.Buffer 325 fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0]) 326 for _, t := range l { 327 fmt.Fprintf(&msg, "\t%v: %v refers to\n", base.FmtPos(typePos(t)), t) 328 t.SetBroke(true) 329 } 330 fmt.Fprintf(&msg, "\t%v: %v", base.FmtPos(typePos(l[0])), l[0]) 331 base.ErrorfAt(typePos(l[0]), msg.String()) 332} 333 334// CalcSize calculates and stores the size and alignment for t. 335// If CalcSizeDisabled is set, and the size/alignment 336// have not already been calculated, it calls Fatal. 337// This is used to prevent data races in the back end. 338func CalcSize(t *Type) { 339 // Calling CalcSize when typecheck tracing enabled is not safe. 340 // See issue #33658. 341 if base.EnableTrace && SkipSizeForTracing { 342 return 343 } 344 if PtrSize == 0 { 345 // Assume this is a test. 346 return 347 } 348 349 if t == nil { 350 return 351 } 352 353 if t.width == -2 { 354 reportTypeLoop(t) 355 t.width = 0 356 t.align = 1 357 return 358 } 359 360 if t.widthCalculated() { 361 return 362 } 363 364 if CalcSizeDisabled { 365 if t.Broke() { 366 // break infinite recursion from Fatal call below 367 return 368 } 369 t.SetBroke(true) 370 base.Fatalf("width not calculated: %v", t) 371 } 372 373 // break infinite recursion if the broken recursive type 374 // is referenced again 375 if t.Broke() && t.width == 0 { 376 return 377 } 378 379 // defer CheckSize calls until after we're done 380 DeferCheckSize() 381 382 lno := base.Pos 383 if pos := t.Pos(); pos.IsKnown() { 384 base.Pos = pos 385 } 386 387 t.width = -2 388 t.align = 0 // 0 means use t.Width, below 389 390 et := t.Kind() 391 switch et { 392 case TFUNC, TCHAN, TMAP, TSTRING: 393 break 394 395 // SimType == 0 during bootstrap 396 default: 397 if SimType[t.Kind()] != 0 { 398 et = SimType[t.Kind()] 399 } 400 } 401 402 var w int64 403 switch et { 404 default: 405 base.Fatalf("CalcSize: unknown type: %v", t) 406 407 // compiler-specific stuff 408 case TINT8, TUINT8, TBOOL: 409 // bool is int8 410 w = 1 411 412 case TINT16, TUINT16: 413 w = 2 414 415 case TINT32, TUINT32, TFLOAT32: 416 w = 4 417 418 case TINT64, TUINT64, TFLOAT64: 419 w = 8 420 t.align = uint8(RegSize) 421 422 case TCOMPLEX64: 423 w = 8 424 t.align = 4 425 426 case TCOMPLEX128: 427 w = 16 428 t.align = uint8(RegSize) 429 430 case TPTR: 431 w = int64(PtrSize) 432 CheckSize(t.Elem()) 433 434 case TUNSAFEPTR: 435 w = int64(PtrSize) 436 437 case TINTER: // implemented as 2 pointers 438 w = 2 * int64(PtrSize) 439 t.align = uint8(PtrSize) 440 expandiface(t) 441 442 case TUNION: 443 // Always part of an interface for now, so size/align don't matter. 444 // Pretend a union is represented like an interface. 445 w = 2 * int64(PtrSize) 446 t.align = uint8(PtrSize) 447 448 case TCHAN: // implemented as pointer 449 w = int64(PtrSize) 450 451 CheckSize(t.Elem()) 452 453 // Make fake type to trigger channel element size check after 454 // any top-level recursive type has been completed. 455 t1 := NewChanArgs(t) 456 CheckSize(t1) 457 458 case TCHANARGS: 459 t1 := t.ChanArgs() 460 CalcSize(t1) // just in case 461 // Make sure size of t1.Elem() is calculated at this point. We can 462 // use CalcSize() here rather than CheckSize(), because the top-level 463 // (possibly recursive) type will have been calculated before the fake 464 // chanargs is handled. 465 CalcSize(t1.Elem()) 466 if t1.Elem().width >= 1<<16 { 467 base.Errorf("channel element type too large (>64kB)") 468 } 469 w = 1 // anything will do 470 471 case TMAP: // implemented as pointer 472 w = int64(PtrSize) 473 CheckSize(t.Elem()) 474 CheckSize(t.Key()) 475 476 case TFORW: // should have been filled in 477 reportTypeLoop(t) 478 w = 1 // anything will do 479 480 case TANY: 481 // not a real type; should be replaced before use. 482 base.Fatalf("CalcSize any") 483 484 case TSTRING: 485 if StringSize == 0 { 486 base.Fatalf("early CalcSize string") 487 } 488 w = StringSize 489 t.align = uint8(PtrSize) 490 491 case TARRAY: 492 if t.Elem() == nil { 493 break 494 } 495 496 CalcSize(t.Elem()) 497 if t.Elem().width != 0 { 498 cap := (uint64(MaxWidth) - 1) / uint64(t.Elem().width) 499 if uint64(t.NumElem()) > cap { 500 base.Errorf("type %L larger than address space", t) 501 } 502 } 503 w = t.NumElem() * t.Elem().width 504 t.align = t.Elem().align 505 506 case TSLICE: 507 if t.Elem() == nil { 508 break 509 } 510 w = SliceSize 511 CheckSize(t.Elem()) 512 t.align = uint8(PtrSize) 513 514 case TSTRUCT: 515 if t.IsFuncArgStruct() { 516 base.Fatalf("CalcSize fn struct %v", t) 517 } 518 w = calcStructOffset(t, t, 0, 1) 519 520 // make fake type to check later to 521 // trigger function argument computation. 522 case TFUNC: 523 t1 := NewFuncArgs(t) 524 CheckSize(t1) 525 w = int64(PtrSize) // width of func type is pointer 526 527 // function is 3 cated structures; 528 // compute their widths as side-effect. 529 case TFUNCARGS: 530 t1 := t.FuncArgs() 531 w = calcStructOffset(t1, t1.Recvs(), 0, 0) 532 w = calcStructOffset(t1, t1.Params(), w, RegSize) 533 w = calcStructOffset(t1, t1.Results(), w, RegSize) 534 t1.extra.(*Func).Argwid = w 535 if w%int64(RegSize) != 0 { 536 base.Warn("bad type %v %d\n", t1, w) 537 } 538 t.align = 1 539 540 case TTYPEPARAM: 541 // TODO(danscales) - remove when we eliminate the need 542 // to do CalcSize in noder2 (which shouldn't be needed in the noder) 543 w = int64(PtrSize) 544 } 545 546 if PtrSize == 4 && w != int64(int32(w)) { 547 base.Errorf("type %v too large", t) 548 } 549 550 t.width = w 551 if t.align == 0 { 552 if w == 0 || w > 8 || w&(w-1) != 0 { 553 base.Fatalf("invalid alignment for %v", t) 554 } 555 t.align = uint8(w) 556 } 557 558 base.Pos = lno 559 560 ResumeCheckSize() 561} 562 563// CalcStructSize calculates the size of s, 564// filling in s.Width and s.Align, 565// even if size calculation is otherwise disabled. 566func CalcStructSize(s *Type) { 567 s.width = calcStructOffset(s, s, 0, 1) // sets align 568} 569 570// RecalcSize is like CalcSize, but recalculates t's size even if it 571// has already been calculated before. It does not recalculate other 572// types. 573func RecalcSize(t *Type) { 574 t.align = 0 575 CalcSize(t) 576} 577 578func (t *Type) widthCalculated() bool { 579 return t.align > 0 580} 581 582// when a type's width should be known, we call CheckSize 583// to compute it. during a declaration like 584// 585// type T *struct { next T } 586// 587// it is necessary to defer the calculation of the struct width 588// until after T has been initialized to be a pointer to that struct. 589// similarly, during import processing structs may be used 590// before their definition. in those situations, calling 591// DeferCheckSize() stops width calculations until 592// ResumeCheckSize() is called, at which point all the 593// CalcSizes that were deferred are executed. 594// CalcSize should only be called when the type's size 595// is needed immediately. CheckSize makes sure the 596// size is evaluated eventually. 597 598var deferredTypeStack []*Type 599 600func CheckSize(t *Type) { 601 if t == nil { 602 return 603 } 604 605 // function arg structs should not be checked 606 // outside of the enclosing function. 607 if t.IsFuncArgStruct() { 608 base.Fatalf("CheckSize %v", t) 609 } 610 611 if defercalc == 0 { 612 CalcSize(t) 613 return 614 } 615 616 // if type has not yet been pushed on deferredTypeStack yet, do it now 617 if !t.Deferwidth() { 618 t.SetDeferwidth(true) 619 deferredTypeStack = append(deferredTypeStack, t) 620 } 621} 622 623func DeferCheckSize() { 624 defercalc++ 625} 626 627func ResumeCheckSize() { 628 if defercalc == 1 { 629 for len(deferredTypeStack) > 0 { 630 t := deferredTypeStack[len(deferredTypeStack)-1] 631 deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1] 632 t.SetDeferwidth(false) 633 CalcSize(t) 634 } 635 } 636 637 defercalc-- 638} 639 640// PtrDataSize returns the length in bytes of the prefix of t 641// containing pointer data. Anything after this offset is scalar data. 642// 643// PtrDataSize is only defined for actual Go types. It's an error to 644// use it on compiler-internal types (e.g., TSSA, TRESULTS). 645func PtrDataSize(t *Type) int64 { 646 switch t.Kind() { 647 case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32, 648 TUINT32, TINT64, TUINT64, TINT, TUINT, 649 TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64: 650 return 0 651 652 case TPTR: 653 if t.Elem().NotInHeap() { 654 return 0 655 } 656 return int64(PtrSize) 657 658 case TUNSAFEPTR, TFUNC, TCHAN, TMAP: 659 return int64(PtrSize) 660 661 case TSTRING: 662 // struct { byte *str; intgo len; } 663 return int64(PtrSize) 664 665 case TINTER: 666 // struct { Itab *tab; void *data; } or 667 // struct { Type *type; void *data; } 668 // Note: see comment in typebits.Set 669 return 2 * int64(PtrSize) 670 671 case TSLICE: 672 if t.Elem().NotInHeap() { 673 return 0 674 } 675 // struct { byte *array; uintgo len; uintgo cap; } 676 return int64(PtrSize) 677 678 case TARRAY: 679 if t.NumElem() == 0 { 680 return 0 681 } 682 // t.NumElem() > 0 683 size := PtrDataSize(t.Elem()) 684 if size == 0 { 685 return 0 686 } 687 return (t.NumElem()-1)*t.Elem().Size() + size 688 689 case TSTRUCT: 690 // Find the last field that has pointers, if any. 691 fs := t.Fields().Slice() 692 for i := len(fs) - 1; i >= 0; i-- { 693 if size := PtrDataSize(fs[i].Type); size > 0 { 694 return fs[i].Offset + size 695 } 696 } 697 return 0 698 699 default: 700 base.Fatalf("PtrDataSize: unexpected type, %v", t) 701 return 0 702 } 703} 704