Commit 4e841748 authored by Ian Lance Taylor's avatar Ian Lance Taylor

Separate the alignment of a field from the alignment of the

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
parent aacdc253
......@@ -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
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment