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
|
|
|
|
|
|
|
|
|
|
import "cmd/internal/obj"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* machine size and rounding
|
|
|
|
|
* alignment is dictated around
|
|
|
|
|
* the size of a pointer, set in betypeinit
|
|
|
|
|
* (see ../6g/galign.c).
|
|
|
|
|
*/
|
|
|
|
|
var defercalc int
|
|
|
|
|
|
|
|
|
|
func Rnd(o int64, r int64) int64 {
|
|
|
|
|
if r < 1 || r > 8 || r&(r-1) != 0 {
|
|
|
|
|
Fatal("rnd %d", r)
|
|
|
|
|
}
|
|
|
|
|
return (o + r - 1) &^ (r - 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func offmod(t *Type) {
|
2015-02-23 16:07:24 -05:00
|
|
|
o := int32(0)
|
|
|
|
|
for f := t.Type; f != nil; f = f.Down {
|
2015-02-13 14:40:36 -05:00
|
|
|
if f.Etype != TFIELD {
|
|
|
|
|
Fatal("offmod: not TFIELD: %v", Tconv(f, obj.FmtLong))
|
|
|
|
|
}
|
|
|
|
|
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 {
|
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
|
|
|
|
|
for f := t.Type; f != nil; f = f.Down {
|
2015-02-13 14:40:36 -05:00
|
|
|
if f.Etype != TFIELD {
|
|
|
|
|
Fatal("widstruct: not TFIELD: %v", Tconv(f, obj.FmtLong))
|
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
|
Fatal("invalid width %d", f.Type.Width)
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
// in typecheck.c. usually addrescapes runs after
|
|
|
|
|
// 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 {
|
|
|
|
|
Yyerror("type %v too large", Tconv(errtype, obj.FmtLong))
|
|
|
|
|
o = 8 // small but nonzero
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For nonzero-sized structs which end in a zero-sized thing, we add
|
|
|
|
|
// an extra byte of padding to the type. This padding ensures that
|
|
|
|
|
// taking the address of the zero-sized thing can't manufacture a
|
|
|
|
|
// pointer to the next object in the heap. See issue 9401.
|
|
|
|
|
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 {
|
|
|
|
|
Fatal("dowidth without betypeinit")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Width > 0 {
|
2015-06-24 07:23:40 -07:00
|
|
|
if t.Align == 0 {
|
|
|
|
|
// See issue 11354
|
|
|
|
|
Fatal("zero alignment with nonzero size %v", t)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Width == -2 {
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := int(lineno)
|
2015-02-13 14:40:36 -05:00
|
|
|
lineno = int32(t.Lineno)
|
2015-02-17 22:13:49 -05:00
|
|
|
if t.Broke == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
t.Broke = 1
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("invalid recursive type %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Width = 0
|
|
|
|
|
lineno = int32(lno)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// break infinite recursion if the broken recursive type
|
|
|
|
|
// is referenced again
|
|
|
|
|
if t.Broke != 0 && t.Width == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// defer checkwidth calls until after we're done
|
|
|
|
|
defercalc++
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := int(lineno)
|
2015-02-13 14:40:36 -05:00
|
|
|
lineno = int32(t.Lineno)
|
|
|
|
|
t.Width = -2
|
|
|
|
|
t.Align = 0
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
et := int32(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
|
|
|
|
|
|
|
|
|
|
/* simtype == 0 during bootstrap */
|
|
|
|
|
default:
|
|
|
|
|
if Simtype[t.Etype] != 0 {
|
|
|
|
|
et = int32(Simtype[t.Etype])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
w := int64(0)
|
2015-02-13 14:40:36 -05:00
|
|
|
switch et {
|
|
|
|
|
default:
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("dowidth: unknown type: %v", t)
|
2015-02-13 14:40:36 -05: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)
|
|
|
|
|
checkwidth(t.Down)
|
|
|
|
|
|
|
|
|
|
case TFORW: // should have been filled in
|
2015-02-17 22:13:49 -05:00
|
|
|
if t.Broke == 0 {
|
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
|
|
|
|
|
|
|
|
|
|
// dummy type; should be replaced before use.
|
|
|
|
|
case TANY:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Debug['A'] == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("dowidth any")
|
|
|
|
|
}
|
|
|
|
|
w = 1 // anything will do
|
|
|
|
|
|
|
|
|
|
case TSTRING:
|
|
|
|
|
if sizeof_String == 0 {
|
|
|
|
|
Fatal("early dowidth string")
|
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
|
Yyerror("type %v larger than address space", Tconv(t, obj.FmtLong))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
2015-02-17 22:13:49 -05:00
|
|
|
if t.Broke == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("use of [...] array outside of array literal")
|
|
|
|
|
t.Broke = 1
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("dowidth %v", t) // probably [...]T
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSTRUCT:
|
|
|
|
|
if t.Funarg != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("dowidth fn struct %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
w = widstruct(t, t, 0, 1)
|
|
|
|
|
|
|
|
|
|
// make fake type to check later to
|
|
|
|
|
// 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)
|
|
|
|
|
|
|
|
|
|
// function is 3 cated structures;
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
w = widstruct(t.Type, *getthis(t1), 0, 0)
|
|
|
|
|
w = widstruct(t.Type, *getinarg(t1), w, Widthreg)
|
|
|
|
|
w = widstruct(t.Type, *Getoutarg(t1), w, Widthreg)
|
|
|
|
|
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-04-17 12:03:22 -04:00
|
|
|
Fatal("invalid alignment for %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
t.Align = uint8(w)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lineno = int32(lno)
|
|
|
|
|
|
|
|
|
|
if defercalc == 1 {
|
|
|
|
|
resumecheckwidth()
|
|
|
|
|
} else {
|
|
|
|
|
defercalc--
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
type TypeList struct {
|
|
|
|
|
t *Type
|
|
|
|
|
next *TypeList
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var tlfree *TypeList
|
|
|
|
|
|
|
|
|
|
var tlq *TypeList
|
|
|
|
|
|
|
|
|
|
func checkwidth(t *Type) {
|
|
|
|
|
if t == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// function arg structs should not be checked
|
|
|
|
|
// outside of the enclosing function.
|
|
|
|
|
if t.Funarg != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
Fatal("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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Deferwidth != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
t.Deferwidth = 1
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
l := tlfree
|
2015-02-13 14:40:36 -05:00
|
|
|
if l != nil {
|
|
|
|
|
tlfree = l.next
|
|
|
|
|
} else {
|
|
|
|
|
l = new(TypeList)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.t = t
|
|
|
|
|
l.next = tlq
|
|
|
|
|
tlq = l
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func defercheckwidth() {
|
|
|
|
|
// we get out of sync on syntax errors, so don't be pedantic.
|
|
|
|
|
if defercalc != 0 && nerrors == 0 {
|
|
|
|
|
Fatal("defercheckwidth")
|
|
|
|
|
}
|
|
|
|
|
defercalc = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func resumecheckwidth() {
|
2015-02-17 22:13:49 -05:00
|
|
|
if defercalc == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("resumecheckwidth")
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := tlq; l != nil; l = tlq {
|
2015-02-13 14:40:36 -05:00
|
|
|
l.t.Deferwidth = 0
|
|
|
|
|
tlq = l.next
|
|
|
|
|
dowidth(l.t)
|
|
|
|
|
l.next = tlfree
|
|
|
|
|
tlfree = l
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
defercalc = 0
|
|
|
|
|
}
|
|
|
|
|
|
cmd/internal/gc: emit write barriers at lower level
This is primarily preparation for inlining, not an optimization by itself,
but it still helps some.
name old new delta
BenchmarkBinaryTree17 18.2s × (0.99,1.01) 17.9s × (0.99,1.01) -1.57%
BenchmarkFannkuch11 4.44s × (1.00,1.00) 4.42s × (1.00,1.00) -0.40%
BenchmarkFmtFprintfEmpty 119ns × (0.95,1.02) 118ns × (0.96,1.02) ~
BenchmarkFmtFprintfString 501ns × (0.99,1.02) 486ns × (0.99,1.01) -2.89%
BenchmarkFmtFprintfInt 474ns × (0.99,1.00) 457ns × (0.99,1.01) -3.59%
BenchmarkFmtFprintfIntInt 792ns × (1.00,1.00) 768ns × (1.00,1.01) -3.03%
BenchmarkFmtFprintfPrefixedInt 574ns × (1.00,1.01) 584ns × (0.99,1.03) +1.83%
BenchmarkFmtFprintfFloat 749ns × (1.00,1.00) 739ns × (0.99,1.00) -1.34%
BenchmarkFmtManyArgs 2.94µs × (1.00,1.01) 2.77µs × (1.00,1.00) -5.76%
BenchmarkGobDecode 39.5ms × (0.99,1.01) 39.3ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (1.00,1.01) 39.4ms × (0.99,1.00) ~
BenchmarkGzip 658ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) +0.22%
BenchmarkHTTPClientServer 134µs × (0.99,1.01) 133µs × (0.98,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 56.5ms × (0.99,1.01) ~
BenchmarkJSONDecode 141ms × (1.00,1.00) 143ms × (1.00,1.00) +1.09%
BenchmarkMandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~
BenchmarkGoParse 10.1ms × (0.91,1.09) 9.6ms × (0.94,1.07) ~
BenchmarkRegexpMatchEasy0_32 207ns × (1.00,1.01) 210ns × (1.00,1.00) +1.45%
BenchmarkRegexpMatchEasy0_1K 592ns × (0.99,1.00) 596ns × (0.99,1.01) +0.68%
BenchmarkRegexpMatchEasy1_32 184ns × (0.99,1.01) 184ns × (0.99,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.00) 1.01µs × (0.99,1.01) ~
BenchmarkRegexpMatchMedium_32 327ns × (0.99,1.00) 327ns × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_1K 92.5µs × (1.00,1.00) 93.0µs × (1.00,1.02) +0.48%
BenchmarkRegexpMatchHard_32 4.79µs × (0.95,1.00) 4.76µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.00) 136µs × (1.00,1.01) ~
BenchmarkRevcomp 900ms × (0.99,1.01) 892ms × (1.00,1.01) ~
BenchmarkTemplate 170ms × (0.99,1.01) 175ms × (0.99,1.00) +2.95%
BenchmarkTimeParse 645ns × (1.00,1.00) 638ns × (1.00,1.00) -1.16%
BenchmarkTimeFormat 740ns × (1.00,1.00) 772ns × (1.00,1.00) +4.39%
Change-Id: I0be905e32791e0cb70ff01f169c4b309a971d981
Reviewed-on: https://go-review.googlesource.com/9159
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-04-17 00:25:10 -04:00
|
|
|
var itable *Type // distinguished *byte
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func typeinit() {
|
|
|
|
|
if Widthptr == 0 {
|
|
|
|
|
Fatal("typeinit before betypeinit")
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := 0; i < NTYPE; i++ {
|
2015-02-13 14:40:36 -05:00
|
|
|
Simtype[i] = uint8(i)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Types[TPTR32] = typ(TPTR32)
|
|
|
|
|
dowidth(Types[TPTR32])
|
|
|
|
|
|
|
|
|
|
Types[TPTR64] = typ(TPTR64)
|
|
|
|
|
dowidth(Types[TPTR64])
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
t := typ(TUNSAFEPTR)
|
2015-02-13 14:40:36 -05:00
|
|
|
Types[TUNSAFEPTR] = t
|
|
|
|
|
t.Sym = Pkglookup("Pointer", unsafepkg)
|
|
|
|
|
t.Sym.Def = typenod(t)
|
2015-05-26 23:08:39 -04:00
|
|
|
t.Sym.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
dowidth(Types[TUNSAFEPTR])
|
|
|
|
|
|
|
|
|
|
Tptr = TPTR32
|
|
|
|
|
if Widthptr == 8 {
|
|
|
|
|
Tptr = TPTR64
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := TINT8; i <= TUINT64; i++ {
|
2015-03-01 07:54:01 +00:00
|
|
|
Isint[i] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-01 07:54:01 +00:00
|
|
|
Isint[TINT] = true
|
|
|
|
|
Isint[TUINT] = true
|
|
|
|
|
Isint[TUINTPTR] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
Isfloat[TFLOAT32] = true
|
|
|
|
|
Isfloat[TFLOAT64] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
Iscomplex[TCOMPLEX64] = true
|
|
|
|
|
Iscomplex[TCOMPLEX128] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
Isptr[TPTR32] = true
|
|
|
|
|
Isptr[TPTR64] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
isforw[TFORW] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
Issigned[TINT] = true
|
|
|
|
|
Issigned[TINT8] = true
|
|
|
|
|
Issigned[TINT16] = true
|
|
|
|
|
Issigned[TINT32] = true
|
|
|
|
|
Issigned[TINT64] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* initialize okfor
|
|
|
|
|
*/
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := 0; i < NTYPE; i++ {
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isint[i] || i == TIDEAL {
|
|
|
|
|
okforeq[i] = true
|
|
|
|
|
okforcmp[i] = true
|
|
|
|
|
okforarith[i] = true
|
|
|
|
|
okforadd[i] = true
|
|
|
|
|
okforand[i] = true
|
|
|
|
|
okforconst[i] = true
|
|
|
|
|
issimple[i] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
Minintval[i] = new(Mpint)
|
|
|
|
|
Maxintval[i] = new(Mpint)
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isfloat[i] {
|
|
|
|
|
okforeq[i] = true
|
|
|
|
|
okforcmp[i] = true
|
|
|
|
|
okforadd[i] = true
|
|
|
|
|
okforarith[i] = true
|
|
|
|
|
okforconst[i] = true
|
|
|
|
|
issimple[i] = true
|
2015-03-20 16:59:08 -07:00
|
|
|
minfltval[i] = newMpflt()
|
|
|
|
|
maxfltval[i] = newMpflt()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if Iscomplex[i] {
|
|
|
|
|
okforeq[i] = true
|
|
|
|
|
okforadd[i] = true
|
|
|
|
|
okforarith[i] = true
|
|
|
|
|
okforconst[i] = true
|
|
|
|
|
issimple[i] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
issimple[TBOOL] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforadd[TSTRING] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforbool[TBOOL] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforcap[TARRAY] = true
|
|
|
|
|
okforcap[TCHAN] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforconst[TBOOL] = true
|
|
|
|
|
okforconst[TSTRING] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforlen[TARRAY] = true
|
|
|
|
|
okforlen[TCHAN] = true
|
|
|
|
|
okforlen[TMAP] = true
|
|
|
|
|
okforlen[TSTRING] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforeq[TPTR32] = true
|
|
|
|
|
okforeq[TPTR64] = true
|
|
|
|
|
okforeq[TUNSAFEPTR] = true
|
|
|
|
|
okforeq[TINTER] = true
|
|
|
|
|
okforeq[TCHAN] = true
|
|
|
|
|
okforeq[TSTRING] = true
|
|
|
|
|
okforeq[TBOOL] = true
|
|
|
|
|
okforeq[TMAP] = true // nil only; refined in typecheck
|
|
|
|
|
okforeq[TFUNC] = true // nil only; refined in typecheck
|
|
|
|
|
okforeq[TARRAY] = true // nil slice only; refined in typecheck
|
|
|
|
|
okforeq[TSTRUCT] = true // it's complicated; refined in typecheck
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
okforcmp[TSTRING] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var i int
|
2015-02-13 14:40:36 -05:00
|
|
|
for i = 0; i < len(okfor); i++ {
|
|
|
|
|
okfor[i] = okfornone[:]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// binary
|
|
|
|
|
okfor[OADD] = okforadd[:]
|
|
|
|
|
|
|
|
|
|
okfor[OAND] = okforand[:]
|
|
|
|
|
okfor[OANDAND] = okforbool[:]
|
|
|
|
|
okfor[OANDNOT] = okforand[:]
|
|
|
|
|
okfor[ODIV] = okforarith[:]
|
|
|
|
|
okfor[OEQ] = okforeq[:]
|
|
|
|
|
okfor[OGE] = okforcmp[:]
|
|
|
|
|
okfor[OGT] = okforcmp[:]
|
|
|
|
|
okfor[OLE] = okforcmp[:]
|
|
|
|
|
okfor[OLT] = okforcmp[:]
|
|
|
|
|
okfor[OMOD] = okforand[:]
|
2015-06-23 18:59:52 -05:00
|
|
|
okfor[OHMUL] = okforarith[:]
|
2015-02-13 14:40:36 -05:00
|
|
|
okfor[OMUL] = okforarith[:]
|
|
|
|
|
okfor[ONE] = okforeq[:]
|
|
|
|
|
okfor[OOR] = okforand[:]
|
|
|
|
|
okfor[OOROR] = okforbool[:]
|
|
|
|
|
okfor[OSUB] = okforarith[:]
|
|
|
|
|
okfor[OXOR] = okforand[:]
|
|
|
|
|
okfor[OLSH] = okforand[:]
|
|
|
|
|
okfor[ORSH] = okforand[:]
|
|
|
|
|
|
|
|
|
|
// unary
|
|
|
|
|
okfor[OCOM] = okforand[:]
|
|
|
|
|
|
|
|
|
|
okfor[OMINUS] = okforarith[:]
|
|
|
|
|
okfor[ONOT] = okforbool[:]
|
|
|
|
|
okfor[OPLUS] = okforarith[:]
|
|
|
|
|
|
|
|
|
|
// special
|
|
|
|
|
okfor[OCAP] = okforcap[:]
|
|
|
|
|
|
|
|
|
|
okfor[OLEN] = okforlen[:]
|
|
|
|
|
|
|
|
|
|
// comparison
|
2015-03-01 07:54:01 +00:00
|
|
|
iscmp[OLT] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
iscmp[OGT] = true
|
|
|
|
|
iscmp[OGE] = true
|
|
|
|
|
iscmp[OLE] = true
|
|
|
|
|
iscmp[OEQ] = true
|
|
|
|
|
iscmp[ONE] = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
mpatofix(Maxintval[TINT8], "0x7f")
|
|
|
|
|
mpatofix(Minintval[TINT8], "-0x80")
|
|
|
|
|
mpatofix(Maxintval[TINT16], "0x7fff")
|
|
|
|
|
mpatofix(Minintval[TINT16], "-0x8000")
|
|
|
|
|
mpatofix(Maxintval[TINT32], "0x7fffffff")
|
|
|
|
|
mpatofix(Minintval[TINT32], "-0x80000000")
|
|
|
|
|
mpatofix(Maxintval[TINT64], "0x7fffffffffffffff")
|
|
|
|
|
mpatofix(Minintval[TINT64], "-0x8000000000000000")
|
|
|
|
|
|
|
|
|
|
mpatofix(Maxintval[TUINT8], "0xff")
|
|
|
|
|
mpatofix(Maxintval[TUINT16], "0xffff")
|
|
|
|
|
mpatofix(Maxintval[TUINT32], "0xffffffff")
|
|
|
|
|
mpatofix(Maxintval[TUINT64], "0xffffffffffffffff")
|
|
|
|
|
|
|
|
|
|
/* f is valid float if min < f < max. (min and max are not themselves valid.) */
|
|
|
|
|
mpatoflt(maxfltval[TFLOAT32], "33554431p103") /* 2^24-1 p (127-23) + 1/2 ulp*/
|
|
|
|
|
mpatoflt(minfltval[TFLOAT32], "-33554431p103")
|
|
|
|
|
mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970") /* 2^53-1 p (1023-52) + 1/2 ulp */
|
|
|
|
|
mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970")
|
|
|
|
|
|
|
|
|
|
maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]
|
|
|
|
|
minfltval[TCOMPLEX64] = minfltval[TFLOAT32]
|
|
|
|
|
maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]
|
|
|
|
|
minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
|
|
|
|
|
|
|
|
|
|
/* for walk to use in error messages */
|
|
|
|
|
Types[TFUNC] = functype(nil, nil, nil)
|
|
|
|
|
|
|
|
|
|
/* types used in front end */
|
|
|
|
|
// types[TNIL] got set early in lexinit
|
|
|
|
|
Types[TIDEAL] = typ(TIDEAL)
|
|
|
|
|
|
|
|
|
|
Types[TINTER] = typ(TINTER)
|
|
|
|
|
|
|
|
|
|
/* simple aliases */
|
|
|
|
|
Simtype[TMAP] = uint8(Tptr)
|
|
|
|
|
|
|
|
|
|
Simtype[TCHAN] = uint8(Tptr)
|
|
|
|
|
Simtype[TFUNC] = uint8(Tptr)
|
|
|
|
|
Simtype[TUNSAFEPTR] = uint8(Tptr)
|
|
|
|
|
|
|
|
|
|
/* pick up the backend thearch.typedefs */
|
2015-02-23 16:07:24 -05:00
|
|
|
var s1 *Sym
|
|
|
|
|
var etype int
|
|
|
|
|
var sameas int
|
|
|
|
|
var s *Sym
|
2015-02-13 14:40:36 -05:00
|
|
|
for i = range Thearch.Typedefs {
|
|
|
|
|
s = Lookup(Thearch.Typedefs[i].Name)
|
|
|
|
|
s1 = Pkglookup(Thearch.Typedefs[i].Name, builtinpkg)
|
|
|
|
|
|
|
|
|
|
etype = Thearch.Typedefs[i].Etype
|
|
|
|
|
if etype < 0 || etype >= len(Types) {
|
|
|
|
|
Fatal("typeinit: %s bad etype", s.Name)
|
|
|
|
|
}
|
|
|
|
|
sameas = Thearch.Typedefs[i].Sameas
|
|
|
|
|
if sameas < 0 || sameas >= len(Types) {
|
|
|
|
|
Fatal("typeinit: %s bad sameas", s.Name)
|
|
|
|
|
}
|
|
|
|
|
Simtype[etype] = uint8(sameas)
|
|
|
|
|
minfltval[etype] = minfltval[sameas]
|
|
|
|
|
maxfltval[etype] = maxfltval[sameas]
|
|
|
|
|
Minintval[etype] = Minintval[sameas]
|
|
|
|
|
Maxintval[etype] = Maxintval[sameas]
|
|
|
|
|
|
|
|
|
|
t = Types[etype]
|
|
|
|
|
if t != nil {
|
|
|
|
|
Fatal("typeinit: %s already defined", s.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t = typ(etype)
|
|
|
|
|
t.Sym = s1
|
|
|
|
|
|
|
|
|
|
dowidth(t)
|
|
|
|
|
Types[etype] = t
|
|
|
|
|
s1.Def = typenod(t)
|
2015-05-26 23:08:39 -04:00
|
|
|
s1.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Array_array = int(Rnd(0, int64(Widthptr)))
|
|
|
|
|
Array_nel = int(Rnd(int64(Array_array)+int64(Widthptr), int64(Widthint)))
|
|
|
|
|
Array_cap = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthint)))
|
|
|
|
|
sizeof_Array = int(Rnd(int64(Array_cap)+int64(Widthint), int64(Widthptr)))
|
|
|
|
|
|
|
|
|
|
// string is same as slice wo the cap
|
|
|
|
|
sizeof_String = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthptr)))
|
|
|
|
|
|
|
|
|
|
dowidth(Types[TSTRING])
|
|
|
|
|
dowidth(idealstring)
|
cmd/internal/gc: emit write barriers at lower level
This is primarily preparation for inlining, not an optimization by itself,
but it still helps some.
name old new delta
BenchmarkBinaryTree17 18.2s × (0.99,1.01) 17.9s × (0.99,1.01) -1.57%
BenchmarkFannkuch11 4.44s × (1.00,1.00) 4.42s × (1.00,1.00) -0.40%
BenchmarkFmtFprintfEmpty 119ns × (0.95,1.02) 118ns × (0.96,1.02) ~
BenchmarkFmtFprintfString 501ns × (0.99,1.02) 486ns × (0.99,1.01) -2.89%
BenchmarkFmtFprintfInt 474ns × (0.99,1.00) 457ns × (0.99,1.01) -3.59%
BenchmarkFmtFprintfIntInt 792ns × (1.00,1.00) 768ns × (1.00,1.01) -3.03%
BenchmarkFmtFprintfPrefixedInt 574ns × (1.00,1.01) 584ns × (0.99,1.03) +1.83%
BenchmarkFmtFprintfFloat 749ns × (1.00,1.00) 739ns × (0.99,1.00) -1.34%
BenchmarkFmtManyArgs 2.94µs × (1.00,1.01) 2.77µs × (1.00,1.00) -5.76%
BenchmarkGobDecode 39.5ms × (0.99,1.01) 39.3ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (1.00,1.01) 39.4ms × (0.99,1.00) ~
BenchmarkGzip 658ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) +0.22%
BenchmarkHTTPClientServer 134µs × (0.99,1.01) 133µs × (0.98,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 56.5ms × (0.99,1.01) ~
BenchmarkJSONDecode 141ms × (1.00,1.00) 143ms × (1.00,1.00) +1.09%
BenchmarkMandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~
BenchmarkGoParse 10.1ms × (0.91,1.09) 9.6ms × (0.94,1.07) ~
BenchmarkRegexpMatchEasy0_32 207ns × (1.00,1.01) 210ns × (1.00,1.00) +1.45%
BenchmarkRegexpMatchEasy0_1K 592ns × (0.99,1.00) 596ns × (0.99,1.01) +0.68%
BenchmarkRegexpMatchEasy1_32 184ns × (0.99,1.01) 184ns × (0.99,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.00) 1.01µs × (0.99,1.01) ~
BenchmarkRegexpMatchMedium_32 327ns × (0.99,1.00) 327ns × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_1K 92.5µs × (1.00,1.00) 93.0µs × (1.00,1.02) +0.48%
BenchmarkRegexpMatchHard_32 4.79µs × (0.95,1.00) 4.76µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.00) 136µs × (1.00,1.01) ~
BenchmarkRevcomp 900ms × (0.99,1.01) 892ms × (1.00,1.01) ~
BenchmarkTemplate 170ms × (0.99,1.01) 175ms × (0.99,1.00) +2.95%
BenchmarkTimeParse 645ns × (1.00,1.00) 638ns × (1.00,1.00) -1.16%
BenchmarkTimeFormat 740ns × (1.00,1.00) 772ns × (1.00,1.00) +4.39%
Change-Id: I0be905e32791e0cb70ff01f169c4b309a971d981
Reviewed-on: https://go-review.googlesource.com/9159
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-04-17 00:25:10 -04:00
|
|
|
|
|
|
|
|
itable = typ(Tptr)
|
|
|
|
|
itable.Type = Types[TUINT8]
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* compute total size of f's in/out arguments.
|
|
|
|
|
*/
|
|
|
|
|
func Argsize(t *Type) int {
|
|
|
|
|
var save Iter
|
|
|
|
|
var x int64
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
w := int64(0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
fp := Structfirst(&save, Getoutarg(t))
|
2015-02-13 14:40:36 -05:00
|
|
|
for fp != nil {
|
|
|
|
|
x = fp.Width + fp.Type.Width
|
|
|
|
|
if x > w {
|
|
|
|
|
w = x
|
|
|
|
|
}
|
|
|
|
|
fp = structnext(&save)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fp = funcfirst(&save, t)
|
|
|
|
|
for fp != nil {
|
|
|
|
|
x = fp.Width + fp.Type.Width
|
|
|
|
|
if x > w {
|
|
|
|
|
w = x
|
|
|
|
|
}
|
|
|
|
|
fp = funcnext(&save)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
|
|
|
|
|
if int64(int(w)) != w {
|
|
|
|
|
Fatal("argsize too big")
|
|
|
|
|
}
|
|
|
|
|
return int(w)
|
|
|
|
|
}
|