Skip to content
Permalink
Browse files

cmd/compile: move slice construction to callers of makeslice

Only return a pointer p to the new slices backing array from makeslice.
Makeslice callers then construct sliceheader{p, len, cap} explictly
instead of makeslice returning the slice.

Reduces go binary size by ~0.2%.
Removes 92 (~3.5%) panicindex calls from go binary.

Change-Id: I29b7c3b5fe8b9dcec96e2c43730575071cfe8a94
Reviewed-on: https://go-review.googlesource.com/c/141822
Run-TryBot: Martin Möhrmann <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
  • Loading branch information...
martisch committed Oct 14, 2018
1 parent c86d464 commit 020a18c545bf49ffc087ca93cd238195d8dcc411

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -153,8 +153,8 @@ func selectsetpc(cas *byte)
func selectgo(cas0 *byte, order0 *byte, ncases int) (int, bool)
func block()

func makeslice(typ *byte, len int, cap int) (ary []any)
func makeslice64(typ *byte, len int64, cap int64) (ary []any)
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
func growslice(typ *byte, old []any, cap int) (ary []any)
func memmove(to *any, frm *any, length uintptr)
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -2321,6 +2321,12 @@ func (s *state) expr(n *Node) *ssa.Value {
data := s.expr(n.Right)
return s.newValue2(ssa.OpIMake, n.Type, tab, data)

case OSLICEHEADER:
p := s.expr(n.Left)
l := s.expr(n.List.First())
c := s.expr(n.List.Second())
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)

case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
v := s.expr(n.Left)
var i, j, k *ssa.Value
@@ -636,65 +636,66 @@ const (
ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int or type Int = int

ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right
ONE // Left != Right
OLT // Left < Right
OLE // Left <= Right
OGE // Left >= Right
OGT // Left > Right
OIND // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
OMUL // Left * Right
ODIV // Left / Right
OMOD // Left % Right
OLSH // Left << Right
ORSH // Left >> Right
OAND // Left & Right
OANDNOT // Left &^ Right
ONEW // new(Left)
ONOT // !Left
OCOM // ^Left
OPLUS // +Left
OMINUS // -Left
OOROR // Left || Right
OPANIC // panic(Left)
OPRINT // print(List)
OPRINTN // println(List)
OPAREN // (Left)
OSEND // Left <- Right
OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice)
OSLICEARR // Left[List[0] : List[1]] (Left is array)
OSLICESTR // Left[List[0] : List[1]] (Left is string)
OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice)
OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is array)
ORECOVER // recover()
ORECV // <-Left
ORUNESTR // Type(Left) (Type is string, Left is rune)
OSELRECV // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV)
OSELRECV2 // List = <-Right.Left: (apperas as .Left of OCASE; count(List) == 2, Right.Op == ORECV)
OIOTA // iota
OREAL // real(Left)
OIMAG // imag(Left)
OCOMPLEX // complex(Left, Right)
OALIGNOF // unsafe.Alignof(Left)
OOFFSETOF // unsafe.Offsetof(Left)
OSIZEOF // unsafe.Sizeof(Left)
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right
ONE // Left != Right
OLT // Left < Right
OLE // Left <= Right
OGE // Left >= Right
OGT // Left > Right
OIND // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
OMUL // Left * Right
ODIV // Left / Right
OMOD // Left % Right
OLSH // Left << Right
ORSH // Left >> Right
OAND // Left & Right
OANDNOT // Left &^ Right
ONEW // new(Left)
ONOT // !Left
OCOM // ^Left
OPLUS // +Left
OMINUS // -Left
OOROR // Left || Right
OPANIC // panic(Left)
OPRINT // print(List)
OPRINTN // println(List)
OPAREN // (Left)
OSEND // Left <- Right
OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice)
OSLICEARR // Left[List[0] : List[1]] (Left is array)
OSLICESTR // Left[List[0] : List[1]] (Left is string)
OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice)
OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is array)
OSLICEHEADER // sliceheader{Left, List[0], List[1]} (Left is unsafe.Pointer, List[0] is length, List[1] is capacity)
ORECOVER // recover()
ORECV // <-Left
ORUNESTR // Type(Left) (Type is string, Left is rune)
OSELRECV // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV)
OSELRECV2 // List = <-Right.Left: (apperas as .Left of OCASE; count(List) == 2, Right.Op == ORECV)
OIOTA // iota
OREAL // real(Left)
OIMAG // imag(Left)
OCOMPLEX // complex(Left, Right)
OALIGNOF // unsafe.Alignof(Left)
OOFFSETOF // unsafe.Offsetof(Left)
OSIZEOF // unsafe.Sizeof(Left)

// statements
OBLOCK // { List } (block of code)
@@ -1086,6 +1086,47 @@ func typecheck1(n *Node, top int) *Node {
n.Right = assignconv(r, t.Elem(), "send")
n.Type = nil

case OSLICEHEADER:
// Errors here are Fatalf instead of yyerror because only the compiler
// can construct an OSLICEHEADER node.
// Components used in OSLICEHEADER that are supplied by parsed source code
// have already been typechecked in e.g. OMAKESLICE earlier.
ok |= Erv

t := n.Type
if !t.IsSlice() {
Fatalf("invalid type %v for OSLICEHEADER", n.Type)
}

if !n.Left.Type.IsUnsafePtr() {
Fatalf("need unsafe.Pointer for OSLICEHEADER")
}

if x := n.List.Len(); x != 2 {
Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
}

n.Left = typecheck(n.Left, Erv)
l := typecheck(n.List.First(), Erv)
c := typecheck(n.List.Second(), Erv)
l = defaultlit(l, types.Types[TINT])
c = defaultlit(c, types.Types[TINT])

if Isconst(l, CTINT) && l.Int64() < 0 {
Fatalf("len for OSLICEHEADER must be non-negative")
}

if Isconst(c, CTINT) && c.Int64() < 0 {
Fatalf("cap for OSLICEHEADER must be non-negative")
}

if Isconst(l, CTINT) && Isconst(c, CTINT) && l.Val().U.(*Mpint).Cmp(c.Val().U.(*Mpint)) > 0 {
Fatalf("len larger than cap for OSLICEHEADER")
}

n.List.SetFirst(l)
n.List.SetSecond(c)

case OSLICE, OSLICE3:
ok |= Erv
n.Left = typecheck(n.Left, Erv)
@@ -1118,6 +1118,11 @@ opswitch:
case ORECV:
Fatalf("walkexpr ORECV") // should see inside OAS only

case OSLICEHEADER:
n.Left = walkexpr(n.Left, init)
n.List.SetFirst(walkexpr(n.List.First(), init))
n.List.SetSecond(walkexpr(n.List.Second(), init))

case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
n.Left = walkexpr(n.Left, init)
low, high, max := n.SliceBounds()
@@ -1339,8 +1344,13 @@ opswitch:
}

fn := syslook(fnname)
fn = substArgTypes(fn, t.Elem()) // any-1
n = mkcall1(fn, t, init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
n.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
n.Left.SetNonNil(true)
n.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
n.Op = OSLICEHEADER
n.Type = t
n = typecheck(n, Erv)
n = walkexpr(n, init)
}

case ORUNESTR:
@@ -266,8 +266,11 @@ func testGdbPython(t *testing.T, cgo bool) {
infoLocalsRe1 := regexp.MustCompile(`slicevar *= *\[\]string *= *{"def"}`)
// Format output from gdb v8.2
infoLocalsRe2 := regexp.MustCompile(`^slicevar = .*\nmapvar = .*\nstrvar = 0x[0-9a-f]+ "abc"`)
// Format output from gdb v7.7
infoLocalsRe3 := regexp.MustCompile(`^mapvar = .*\nstrvar = "abc"\nslicevar *= *\[\]string`)
if bl := blocks["info locals"]; !infoLocalsRe1.MatchString(bl) &&
!infoLocalsRe2.MatchString(bl) {
!infoLocalsRe2.MatchString(bl) &&
!infoLocalsRe3.MatchString(bl) {
t.Fatalf("info locals failed: %s", bl)
}

@@ -31,7 +31,7 @@ func panicmakeslicecap() {
panic(errorString("makeslice: cap out of range"))
}

func makeslice(et *_type, len, cap int) slice {
func makeslice(et *_type, len, cap int) unsafe.Pointer {
mem, overflow := math.MulUintptr(et.size, uintptr(cap))
if overflow || mem > maxAlloc || len < 0 || len > cap {
// NOTE: Produce a 'len out of range' error instead of a
@@ -45,12 +45,11 @@ func makeslice(et *_type, len, cap int) slice {
}
panicmakeslicecap()
}
p := mallocgc(mem, et, true)

return slice{p, len, cap}
return mallocgc(mem, et, true)
}

func makeslice64(et *_type, len64, cap64 int64) slice {
func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
len := int(len64)
if int64(len) != len64 {
panicmakeslicelen()

0 comments on commit 020a18c

Please sign in to comment.
You can’t perform that action at this time.