]> Cypherpunks repositories - gostls13.git/commitdiff
Separate the alignment of a field from the alignment of the
authorIan Lance Taylor <iant@golang.org>
Tue, 31 Mar 2009 06:19:31 +0000 (23:19 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 31 Mar 2009 06:19:31 +0000 (23:19 -0700)
type of the field.  Use the field alignment to compute the
size of a structure.

This may help 8g but is mainly for gccgo.  gccgo maintains the
standard C/C++ ABI for structure field alignment.  For the
i386, this requires that a float64 field in a struct be
aligned on a 32-bit boundary, although for efficiency a
variable of type float64 or []float64 should be aligned on a
64-bit boundary.

I also removed the unused size field from structField.

R=r
DELTA=117  (75 added, 2 deleted, 40 changed)
OCL=26842
CL=26936

src/lib/reflect/type.go

index 9b3bd35d4d16ef1cc32f49d5230e4130deccf832..7e992a80fc7fef5b4ce3aa4614633cf78dbc2d45 100644 (file)
@@ -52,10 +52,38 @@ const (
        UintptrKind;
 )
 
-var tmp_interface interface{}  // used just to compute sizes of these constants
+// For sizes and alignments.
+
+type allTypes struct {
+       xarray          []byte;
+       xbool           bool;
+       xchan           chan byte;
+       xfloat          float;
+       xfloat32        float32;
+       xfloat64        float64;
+       xint            int;
+       xint16          int16;
+       xint32          int32;
+       xint64          int64;
+       xint8           int8;
+       xinterface      interface {};
+       xmap            map[byte]byte;
+       xptr            *byte;
+       xslice          []byte;
+       xstring         string;
+       xuint           uint;
+       xuint16         uint16;
+       xuint32         uint32;
+       xuint64         uint64;
+       xuint8          uint8;
+       xuintptr        uintptr;
+}
+
+var x allTypes
+
 const (
-       ptrsize = unsafe.Sizeof(&tmp_interface);
-       interfacesize = unsafe.Sizeof(tmp_interface);
+       ptrsize = unsafe.Sizeof(&x);
+       interfacesize = unsafe.Sizeof(x.xinterface);
 )
 
 var missingString = "$missing$"        // syntactic name for undefined type names
@@ -74,6 +102,8 @@ type Type interface {
        String()        string;
        // The number of bytes needed to store a value; analogous to unsafe.Sizeof().
        Size()  int;
+       // The alignment of a value of this type when used as a field in a struct.
+       FieldAlign()    int;
 }
 
 // Fields and methods common to all types
@@ -109,11 +139,16 @@ func (c *commonType) Size() int {
 // -- Basic
 
 type basicType struct {
-       commonType
+       commonType;
+       fieldAlign      int;
+}
+
+func newBasicType(name string, kind int, size int, fieldAlign int) Type {
+       return &basicType{ commonType{kind, name, name, size}, fieldAlign }
 }
 
-func newBasicType(name string, kind int, size int) Type {
-       return &basicType{ commonType{kind, name, name, size} }
+func (t *basicType) FieldAlign() int {
+       return t.fieldAlign
 }
 
 // Prebuilt basic Type objects representing the predeclared basic types.
@@ -121,25 +156,24 @@ func newBasicType(name string, kind int, size int) Type {
 //     Missing represents types whose representation cannot be discovered; usually an error.
 //     DotDotDot represents the pseudo-type of a ... parameter.
 var (
-       Missing = newBasicType(missingString, MissingKind, 1);
-       empty interface{};
-       DotDotDot = newBasicType(dotDotDotString, DotDotDotKind, unsafe.Sizeof(empty));
-       Bool = newBasicType("bool", BoolKind, unsafe.Sizeof(true));
-       Int = newBasicType("int", IntKind, unsafe.Sizeof(int(0)));
-       Int8 = newBasicType("int8", Int8Kind, 1);
-       Int16 = newBasicType("int16", Int16Kind, 2);
-       Int32 = newBasicType("int32", Int32Kind, 4);
-       Int64 = newBasicType("int64", Int64Kind, 8);
-       Uint = newBasicType("uint", UintKind, unsafe.Sizeof(uint(0)));
-       Uint8 = newBasicType("uint8", Uint8Kind, 1);
-       Uint16 = newBasicType("uint16", Uint16Kind, 2);
-       Uint32 = newBasicType("uint32", Uint32Kind, 4);
-       Uint64 = newBasicType("uint64", Uint64Kind, 8);
-       Uintptr = newBasicType("uintptr", UintptrKind, unsafe.Sizeof(uintptr(0)));
-       Float = newBasicType("float", FloatKind, unsafe.Sizeof(float(0)));
-       Float32 = newBasicType("float32", Float32Kind, 4);
-       Float64 = newBasicType("float64", Float64Kind, 8);
-       String = newBasicType("string", StringKind, unsafe.Sizeof(""));
+       Missing = newBasicType(missingString, MissingKind, 1, 1);
+       DotDotDot = newBasicType(dotDotDotString, DotDotDotKind, unsafe.Sizeof(x.xinterface), unsafe.Alignof(x.xinterface));
+       Bool = newBasicType("bool", BoolKind, unsafe.Sizeof(x.xbool), unsafe.Alignof(x.xbool));
+       Int = newBasicType("int", IntKind, unsafe.Sizeof(x.xint), unsafe.Alignof(x.xint));
+       Int8 = newBasicType("int8", Int8Kind, unsafe.Sizeof(x.xint8), unsafe.Alignof(x.xint8));
+       Int16 = newBasicType("int16", Int16Kind, unsafe.Sizeof(x.xint16), unsafe.Alignof(x.xint16));
+       Int32 = newBasicType("int32", Int32Kind, unsafe.Sizeof(x.xint32), unsafe.Alignof(x.xint32));
+       Int64 = newBasicType("int64", Int64Kind, unsafe.Sizeof(x.xint64), unsafe.Alignof(x.xint64));
+       Uint = newBasicType("uint", UintKind, unsafe.Sizeof(x.xuint), unsafe.Alignof(x.xuint));
+       Uint8 = newBasicType("uint8", Uint8Kind, unsafe.Sizeof(x.xuint8), unsafe.Alignof(x.xuint8));
+       Uint16 = newBasicType("uint16", Uint16Kind, unsafe.Sizeof(x.xuint16), unsafe.Alignof(x.xuint16));
+       Uint32 = newBasicType("uint32", Uint32Kind, unsafe.Sizeof(x.xuint32), unsafe.Alignof(x.xuint32));
+       Uint64 = newBasicType("uint64", Uint64Kind, unsafe.Sizeof(x.xuint64), unsafe.Alignof(x.xuint64));
+       Uintptr = newBasicType("uintptr", UintptrKind, unsafe.Sizeof(x.xuintptr), unsafe.Alignof(x.xuintptr));
+       Float = newBasicType("float", FloatKind, unsafe.Sizeof(x.xfloat), unsafe.Alignof(x.xfloat));
+       Float32 = newBasicType("float32", Float32Kind, unsafe.Sizeof(x.xfloat32), unsafe.Alignof(x.xfloat32));
+       Float64 = newBasicType("float64", Float64Kind, unsafe.Sizeof(x.xfloat64), unsafe.Alignof(x.xfloat64));
+       String = newBasicType("string", StringKind, unsafe.Sizeof(x.xstring), unsafe.Alignof(x.xstring));
 )
 
 // Stub types allow us to defer evaluating type names until needed.
@@ -178,6 +212,10 @@ func newPtrTypeStruct(name, typestring string, sub *stubType) *ptrTypeStruct {
        return &ptrTypeStruct{ commonType{PtrKind, typestring, name, ptrsize}, sub}
 }
 
+func (t *ptrTypeStruct) FieldAlign() int {
+       return unsafe.Alignof(x.xptr);
+}
+
 func (t *ptrTypeStruct) Sub() Type {
        return t.sub.Get()
 }
@@ -205,11 +243,18 @@ func newArrayTypeStruct(name, typestring string, open bool, len int, elem *stubT
 
 func (t *arrayTypeStruct) Size() int {
        if t.isslice {
-               return ptrsize*2        // open arrays are 2-word headers
+               return unsafe.Sizeof(x.xslice);
        }
        return t.len * t.elem.Get().Size();
 }
 
+func (t *arrayTypeStruct) FieldAlign() int {
+        if t.isslice {
+               return unsafe.Alignof(x.xslice);
+       }
+       return t.elem.Get().FieldAlign();
+}
+
 func (t *arrayTypeStruct) IsSlice() bool {
        return t.isslice
 }
@@ -244,6 +289,10 @@ func newMapTypeStruct(name, typestring string, key, elem *stubType) *mapTypeStru
        return &mapTypeStruct{ commonType{MapKind, typestring, name, ptrsize}, key, elem}
 }
 
+func (t *mapTypeStruct) FieldAlign() int {
+       return unsafe.Alignof(x.xmap);
+}
+
 func (t *mapTypeStruct) Key() Type {
        return t.key.Get()
 }
@@ -278,6 +327,10 @@ func newChanTypeStruct(name, typestring string, dir int, elem *stubType) *chanTy
        return &chanTypeStruct{ commonType{ChanKind, typestring, name, ptrsize}, elem, dir}
 }
 
+func (t *chanTypeStruct) FieldAlign() int {
+       return unsafe.Alignof(x.xchan);
+}
+
 func (t *chanTypeStruct) Dir() int {
        return t.dir
 }
@@ -302,40 +355,51 @@ type structField struct {
        name    string;
        typ     *stubType;
        tag     string;
-       size    int;
        offset  int;
 }
 
 type structTypeStruct struct {
        commonType;
        field   []structField;
+       fieldAlign      int;
 }
 
 func newStructTypeStruct(name, typestring string, field []structField) *structTypeStruct {
-       return &structTypeStruct{ commonType{StructKind, typestring, name, 0}, field}
+       return &structTypeStruct{ commonType{StructKind, typestring, name, 0}, field, 0}
+}
+
+func (t *structTypeStruct) FieldAlign() int {
+       t.Size();       // Compute size and alignment.
+       return t.fieldAlign
 }
 
-// TODO: not portable; depends on 6g
 func (t *structTypeStruct) Size() int {
        if t.size > 0 {
                return t.size
        }
        size := 0;
-       structalignmask := 7;   // BUG: we know structs are 8-aligned
+       structalign := 0;
        for i := 0; i < len(t.field); i++ {
-               elemsize := t.field[i].typ.Get().Size();
-               // pad until at (elemsize mod 8) boundary
-               align := elemsize - 1;
-               if align > structalignmask {
-                       align = structalignmask
+               typ := t.field[i].typ.Get();
+               elemsize := typ.Size();
+               align := typ.FieldAlign() - 1;
+               if align > structalign {
+                       structalign = align
                }
                if align > 0 {
-                       size = (size + align) & ^align;
+                       size = (size + align) &align;
                }
                t.field[i].offset = size;
                size += elemsize;
        }
-       size = (size + structalignmask) & ^(structalignmask);
+       if (structalign > 0) {
+               // TODO: In the PPC64 ELF ABI, floating point fields
+               // in a struct are aligned to a 4-byte boundary, but
+               // if the first field in the struct is a 64-bit float,
+               // the whole struct is aligned to an 8-byte boundary.
+               size = (size + structalign) &^ structalign;
+               t.fieldAlign = structalign + 1;
+       }
        t.size = size;
        return size;
 }
@@ -372,6 +436,10 @@ func newInterfaceTypeStruct(name, typestring string, field []structField) *inter
        return &interfaceTypeStruct{ commonType{InterfaceKind, typestring, name, interfacesize}, field }
 }
 
+func (t *interfaceTypeStruct) FieldAlign() int {
+       return unsafe.Alignof(x.xinterface);
+}
+
 func (t *interfaceTypeStruct) Field(i int) (name string, typ Type, tag string, offset int) {
        return t.field[i].name, t.field[i].typ.Get(), "", 0
 }
@@ -401,6 +469,11 @@ func newFuncTypeStruct(name, typestring string, in, out *structTypeStruct) *func
        return &funcTypeStruct{ commonType{FuncKind, typestring, name, 0}, in, out }
 }
 
+func (t *funcTypeStruct) FieldAlign() int {
+       panic("reflect.type: func.FieldAlign(): cannot happen");
+       return 0
+}
+
 func (t *funcTypeStruct) Size() int {
        panic("reflect.type: func.Size(): cannot happen");
        return 0
@@ -861,7 +934,7 @@ func (p *typeParser) Type(name string) *stubType {
                if name != "" {
                        // Need to make a copy because we are renaming a basic type
                        b := s.Get();
-                       s = newStubType(name, newBasicType(name, b.Kind(), b.Size()));
+                       s = newStubType(name, newBasicType(name, b.Kind(), b.Size(), b.FieldAlign()));
                }
                return s
        }