From e4f1d9cf2e948eb0f0bb91d7c253ab61dfff3a59 Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Sun, 27 Mar 2016 17:29:53 -0700 Subject: runtime: make execution error panic values implement the Error interface Make execution panics implement Error as mandated by https://golang.org/ref/spec#Run_time_panics, instead of panics with strings. Fixes #14965 Change-Id: I7827f898b9b9c08af541db922cc24fa0800ff18a Reviewed-on: https://go-review.googlesource.com/21214 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/runtime/hashmap.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/runtime/hashmap.go') diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 80b2b5338c..9e18192cd8 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -194,7 +194,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { } if hint < 0 || int64(int32(hint)) != hint { - panic("makemap: size out of range") + panic(plainError("makemap: size out of range")) // TODO: make hint an int, then none of this nonsense } @@ -428,7 +428,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) { if h == nil { - panic("assignment to entry in nil map") + panic(plainError("assignment to entry in nil map")) } if raceenabled { callerpc := getcallerpc(unsafe.Pointer(&t)) -- cgit v1.3 From 974c201f74f730737964e5239da473fc548b408e Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 10 Apr 2016 10:43:04 -0700 Subject: runtime: avoid unnecessary map iteration write barrier Update #14921 Change-Id: I5c5816d0193757bf7465b1e09c27ca06897df4bf Reviewed-on: https://go-review.googlesource.com/21814 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/runtime/hashmap.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/runtime/hashmap.go') diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 9e18192cd8..d549ce4194 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -790,7 +790,9 @@ next: } } it.bucket = bucket - it.bptr = b + if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 + it.bptr = b + } it.i = i + 1 it.checkBucket = checkBucket return -- cgit v1.3 From 4721ea6abcde318a2f5d61ec249cde5e9c57ebea Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 13 Apr 2016 11:22:42 -0400 Subject: runtime/internal/atomic: rename Storep1 to StorepNoWB Make it clear that the point of this function stores a pointer *without* a write barrier. sed -i -e 's/Storep1/StorepNoWB/' $(git grep -l Storep1) Updates #15270. Change-Id: Ifad7e17815e51a738070655fe3b178afdadaecf6 Reviewed-on: https://go-review.googlesource.com/21994 Reviewed-by: Brad Fitzpatrick Reviewed-by: Michael Matloob --- src/runtime/atomic_pointer.go | 4 ++-- src/runtime/hashmap.go | 4 ++-- src/runtime/internal/atomic/asm_386.s | 2 +- src/runtime/internal/atomic/asm_amd64.s | 2 +- src/runtime/internal/atomic/asm_amd64p32.s | 2 +- src/runtime/internal/atomic/asm_mips64x.s | 2 +- src/runtime/internal/atomic/asm_ppc64x.s | 2 +- src/runtime/internal/atomic/atomic_386.go | 2 +- src/runtime/internal/atomic/atomic_amd64x.go | 5 ++++- src/runtime/internal/atomic/atomic_arm.go | 2 +- src/runtime/internal/atomic/atomic_arm64.go | 2 +- src/runtime/internal/atomic/atomic_arm64.s | 2 +- src/runtime/internal/atomic/atomic_mips64x.go | 2 +- src/runtime/internal/atomic/atomic_ppc64x.go | 2 +- src/runtime/internal/atomic/atomic_s390x.go | 2 +- 15 files changed, 20 insertions(+), 17 deletions(-) (limited to 'src/runtime/hashmap.go') diff --git a/src/runtime/atomic_pointer.go b/src/runtime/atomic_pointer.go index d54f1d6eef..e9f5d03b2b 100644 --- a/src/runtime/atomic_pointer.go +++ b/src/runtime/atomic_pointer.go @@ -20,7 +20,7 @@ import ( // //go:nosplit func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { - atomic.Storep1(noescape(ptr), new) + atomic.StorepNoWB(noescape(ptr), new) writebarrierptr_nostore((*uintptr)(ptr), uintptr(new)) } @@ -44,7 +44,7 @@ func sync_atomic_StoreUintptr(ptr *uintptr, new uintptr) //go:nosplit func sync_atomic_StorePointer(ptr *unsafe.Pointer, new unsafe.Pointer) { sync_atomic_StoreUintptr((*uintptr)(unsafe.Pointer(ptr)), uintptr(new)) - atomic.Storep1(noescape(unsafe.Pointer(ptr)), new) + atomic.StorepNoWB(noescape(unsafe.Pointer(ptr)), new) writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new)) } diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index d549ce4194..4f5d03d983 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -1075,8 +1075,8 @@ func mapzero(t *_type) { throw("map element too large") } } - atomic.Storep1(unsafe.Pointer(&zeroptr), persistentalloc(cursize, 64, &memstats.other_sys)) - atomic.Storep1(unsafe.Pointer(&zerosize), unsafe.Pointer(zerosize)) + atomic.StorepNoWB(unsafe.Pointer(&zeroptr), persistentalloc(cursize, 64, &memstats.other_sys)) + atomic.StorepNoWB(unsafe.Pointer(&zerosize), unsafe.Pointer(zerosize)) } unlock(&zerolock) } diff --git a/src/runtime/internal/atomic/asm_386.s b/src/runtime/internal/atomic/asm_386.s index ce84fd83d1..ebecd0b4cb 100644 --- a/src/runtime/internal/atomic/asm_386.s +++ b/src/runtime/internal/atomic/asm_386.s @@ -102,7 +102,7 @@ TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-12 JMP runtime∕internal∕atomic·Xchg(SB) -TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-8 +TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-8 MOVL ptr+0(FP), BX MOVL val+4(FP), AX XCHGL AX, 0(BX) diff --git a/src/runtime/internal/atomic/asm_amd64.s b/src/runtime/internal/atomic/asm_amd64.s index 7463fec4a1..94d4ac2698 100644 --- a/src/runtime/internal/atomic/asm_amd64.s +++ b/src/runtime/internal/atomic/asm_amd64.s @@ -115,7 +115,7 @@ TEXT runtime∕internal∕atomic·Xchg64(SB), NOSPLIT, $0-24 TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-24 JMP runtime∕internal∕atomic·Xchg64(SB) -TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-16 +TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16 MOVQ ptr+0(FP), BX MOVQ val+8(FP), AX XCHGQ AX, 0(BX) diff --git a/src/runtime/internal/atomic/asm_amd64p32.s b/src/runtime/internal/atomic/asm_amd64p32.s index f1e2c3aca6..74c79d08fd 100644 --- a/src/runtime/internal/atomic/asm_amd64p32.s +++ b/src/runtime/internal/atomic/asm_amd64p32.s @@ -115,7 +115,7 @@ TEXT runtime∕internal∕atomic·Xchg64(SB), NOSPLIT, $0-24 TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-12 JMP runtime∕internal∕atomic·Xchg(SB) -TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-8 +TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-8 MOVL ptr+0(FP), BX MOVL val+4(FP), AX XCHGL AX, 0(BX) diff --git a/src/runtime/internal/atomic/asm_mips64x.s b/src/runtime/internal/atomic/asm_mips64x.s index a454f284ab..d0f5c7bdd3 100644 --- a/src/runtime/internal/atomic/asm_mips64x.s +++ b/src/runtime/internal/atomic/asm_mips64x.s @@ -155,7 +155,7 @@ TEXT ·Xchg64(SB), NOSPLIT, $0-24 TEXT ·Xchguintptr(SB), NOSPLIT, $0-24 JMP ·Xchg64(SB) -TEXT ·Storep1(SB), NOSPLIT, $0-16 +TEXT ·StorepNoWB(SB), NOSPLIT, $0-16 JMP ·Store64(SB) TEXT ·Store(SB), NOSPLIT, $0-12 diff --git a/src/runtime/internal/atomic/asm_ppc64x.s b/src/runtime/internal/atomic/asm_ppc64x.s index 45a48b6203..4a776787a2 100644 --- a/src/runtime/internal/atomic/asm_ppc64x.s +++ b/src/runtime/internal/atomic/asm_ppc64x.s @@ -150,7 +150,7 @@ TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-24 BR runtime∕internal∕atomic·Xchg64(SB) -TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-16 +TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16 BR runtime∕internal∕atomic·Store64(SB) TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12 diff --git a/src/runtime/internal/atomic/atomic_386.go b/src/runtime/internal/atomic/atomic_386.go index f4c50b0be1..23a8479515 100644 --- a/src/runtime/internal/atomic/atomic_386.go +++ b/src/runtime/internal/atomic/atomic_386.go @@ -73,4 +73,4 @@ func Store(ptr *uint32, val uint32) func Store64(ptr *uint64, val uint64) // NO go:noescape annotation; see atomic_pointer.go. -func Storep1(ptr unsafe.Pointer, val unsafe.Pointer) +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/internal/atomic/atomic_amd64x.go b/src/runtime/internal/atomic/atomic_amd64x.go index bd40fb3ea2..54851d30f4 100644 --- a/src/runtime/internal/atomic/atomic_amd64x.go +++ b/src/runtime/internal/atomic/atomic_amd64x.go @@ -61,5 +61,8 @@ func Store(ptr *uint32, val uint32) //go:noescape func Store64(ptr *uint64, val uint64) +// StorepNoWB performs *ptr = val atomically and without a write +// barrier. +// // NO go:noescape annotation; see atomic_pointer.go. -func Storep1(ptr unsafe.Pointer, val unsafe.Pointer) +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/internal/atomic/atomic_arm.go b/src/runtime/internal/atomic/atomic_arm.go index c361aef382..244237df4d 100644 --- a/src/runtime/internal/atomic/atomic_arm.go +++ b/src/runtime/internal/atomic/atomic_arm.go @@ -85,7 +85,7 @@ func Loadp(addr unsafe.Pointer) unsafe.Pointer { } //go:nosplit -func Storep1(addr unsafe.Pointer, v unsafe.Pointer) { +func StorepNoWB(addr unsafe.Pointer, v unsafe.Pointer) { for { old := *(*unsafe.Pointer)(addr) if Casp1((*unsafe.Pointer)(addr), old, v) { diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go index 6b32346656..dc82c3396d 100644 --- a/src/runtime/internal/atomic/atomic_arm64.go +++ b/src/runtime/internal/atomic/atomic_arm64.go @@ -77,4 +77,4 @@ func Store(ptr *uint32, val uint32) func Store64(ptr *uint64, val uint64) // NO go:noescape annotation; see atomic_pointer.go. -func Storep1(ptr unsafe.Pointer, val unsafe.Pointer) +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/internal/atomic/atomic_arm64.s b/src/runtime/internal/atomic/atomic_arm64.s index 7b1b0efaf6..eb32f378aa 100644 --- a/src/runtime/internal/atomic/atomic_arm64.s +++ b/src/runtime/internal/atomic/atomic_arm64.s @@ -25,7 +25,7 @@ TEXT ·Loadp(SB),NOSPLIT,$-8-16 MOVD R0, ret+8(FP) RET -TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-16 +TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16 B runtime∕internal∕atomic·Store64(SB) TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12 diff --git a/src/runtime/internal/atomic/atomic_mips64x.go b/src/runtime/internal/atomic/atomic_mips64x.go index 8094db58a0..d06ea4809a 100644 --- a/src/runtime/internal/atomic/atomic_mips64x.go +++ b/src/runtime/internal/atomic/atomic_mips64x.go @@ -53,4 +53,4 @@ func Store(ptr *uint32, val uint32) func Store64(ptr *uint64, val uint64) // NO go:noescape annotation; see atomic_pointer.go. -func Storep1(ptr unsafe.Pointer, val unsafe.Pointer) +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/internal/atomic/atomic_ppc64x.go b/src/runtime/internal/atomic/atomic_ppc64x.go index bf82b82643..72c98eb0c5 100644 --- a/src/runtime/internal/atomic/atomic_ppc64x.go +++ b/src/runtime/internal/atomic/atomic_ppc64x.go @@ -53,4 +53,4 @@ func Store(ptr *uint32, val uint32) func Store64(ptr *uint64, val uint64) // NO go:noescape annotation; see atomic_pointer.go. -func Storep1(ptr unsafe.Pointer, val unsafe.Pointer) +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/internal/atomic/atomic_s390x.go b/src/runtime/internal/atomic/atomic_s390x.go index b6d3d84bdf..9343853485 100644 --- a/src/runtime/internal/atomic/atomic_s390x.go +++ b/src/runtime/internal/atomic/atomic_s390x.go @@ -39,7 +39,7 @@ func Store64(ptr *uint64, val uint64) { // NO go:noescape annotation; see atomic_pointer.go. //go:noinline //go:nosplit -func Storep1(ptr unsafe.Pointer, val unsafe.Pointer) { +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) { *(*uintptr)(ptr) = uintptr(val) } -- cgit v1.3 From 60fd32a47fdffb95d3646c9fc75acc9beff67183 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 19 Apr 2016 08:31:04 -0700 Subject: cmd/compile: change the way we handle large map values mapaccess{1,2} returns a pointer to the value. When the key is not in the map, it returns a pointer to zeroed memory. Currently, for large map values we have a complicated scheme which dynamically allocates zeroed memory for this purpose. It is ugly code and requires an atomic.Load in a bunch of places we'd rather not have it. Switch to a scheme where callsites of mapaccess{1,2} which expect large return values pass in a pointer to zeroed memory that mapaccess can return if the key is not found. This avoids the atomic.Load on all map accesses with a few extra instructions only for the large value acccesses, plus a bit of bss space. There was a time (1.4 & 1.5?) where we did something like this but all the tricks to make the right size zero value were done by the linker. That scheme broke in the presence of dyamic linking. The scheme in this CL works even when dynamic linking. Fixes #12337 Change-Id: Ic2d0319944af33bbb59785938d9ab80958d1b4b1 Reviewed-on: https://go-review.googlesource.com/22221 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Michael Hudson-Doyle --- src/cmd/compile/internal/gc/builtin.go | 2 + src/cmd/compile/internal/gc/builtin/runtime.go | 2 + src/cmd/compile/internal/gc/go.go | 3 ++ src/cmd/compile/internal/gc/main.go | 5 ++ src/cmd/compile/internal/gc/obj.go | 5 ++ src/cmd/compile/internal/gc/reflect.go | 24 ++++++++++ src/cmd/compile/internal/gc/walk.go | 18 +++++-- src/runtime/hashmap.go | 65 +++++++++----------------- src/runtime/hashmap_fast.go | 33 +++++++------ src/runtime/map_test.go | 16 +++++++ 10 files changed, 110 insertions(+), 63 deletions(-) (limited to 'src/runtime/hashmap.go') diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 411c7b8605..b593d11296 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -70,10 +70,12 @@ const runtimeimport = "" + "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + + "func @\"\".mapaccess1_fat (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any, @\"\".zero·5 *byte) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + + "func @\"\".mapaccess2_fat (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any, @\"\".zero·6 *byte) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" + "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" + "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" + diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index 584368a144..e9316cb313 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -89,10 +89,12 @@ func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any) func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any) func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any) +func mapaccess1_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any) func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool) func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) +func mapaccess2_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any, pres bool) func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any) func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) func mapdelete(mapType *byte, hmap map[any]any, key *any) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index af9aaf0dae..87b6121c8e 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -175,6 +175,9 @@ var unsafepkg *Pkg // package unsafe var trackpkg *Pkg // fake package for field tracking +var mappkg *Pkg // fake package for map zero value +var zerosize int64 + var Tptr EType // either TPTR32 or TPTR64 var myimportpath string diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 37e8a17886..2afd262fed 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -137,6 +137,11 @@ func Main() { typepkg = mkpkg("type") typepkg.Name = "type" + // pseudo-package used for map zero values + mappkg = mkpkg("go.map") + mappkg.Name = "go.map" + mappkg.Prefix = "go.map" + goroot = obj.Getgoroot() goos = obj.Getgoos() diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index b60f78f638..fab611fdb5 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -87,6 +87,11 @@ func dumpobj() { dumpglobls() externdcl = tmp + if zerosize > 0 { + zero := Pkglookup("zero", mappkg) + ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA) + } + dumpdata() obj.Writeobjdirect(Ctxt, bout.Writer) diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 5031045c64..4792f88abe 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -1689,3 +1689,27 @@ func (p *GCProg) emit(t *Type, offset int64) { } } } + +// zeroaddr returns the address of a symbol with at least +// size bytes of zeros. +func zeroaddr(size int64) *Node { + if size >= 1<<31 { + Fatalf("map value too big %d", size) + } + if zerosize < size { + zerosize = size + } + s := Pkglookup("zero", mappkg) + if s.Def == nil { + x := newname(s) + x.Type = Types[TUINT8] + x.Class = PEXTERN + x.Typecheck = 1 + s.Def = x + } + z := Nod(OADDR, s.Def, nil) + z.Type = Ptrto(Types[TUINT8]) + z.Addable = true + z.Typecheck = 1 + return z +} diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 82ac74ae33..8cce85de9a 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -864,8 +864,14 @@ opswitch: // a = *var a := n.List.First() - fn := mapfn(p, t) - r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key) + if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero + fn := mapfn(p, t) + r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key) + } else { + fn := mapfn("mapaccess2_fat", t) + z := zeroaddr(w) + r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z) + } // mapaccess2* returns a typed bool, but due to spec changes, // the boolean result of i.(T) is now untyped so we make it the @@ -1222,7 +1228,13 @@ opswitch: p = "mapaccess1" } - n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key) + if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero + n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key) + } else { + p = "mapaccess1_fat" + z := zeroaddr(w) + n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z) + } n = Nod(OIND, n, nil) n.Type = t.Val() n.Typecheck = 1 diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 4f5d03d983..ff59faab5d 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -236,9 +236,6 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { throw("need padding in bucket (value)") } - // make sure zeroptr is large enough - mapzero(t.elem) - // find size parameter which will hold the requested # of elements B := uint8(0) for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<2GB zero on 32-bit machine - throw("map element too large") - } - } - atomic.StorepNoWB(unsafe.Pointer(&zeroptr), persistentalloc(cursize, 64, &memstats.other_sys)) - atomic.StorepNoWB(unsafe.Pointer(&zerosize), unsafe.Pointer(zerosize)) - } - unlock(&zerolock) -} +const maxZero = 1024 // must match value in ../cmd/compile/internal/gc/walk.go +var zeroVal [maxZero]byte diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go index 6a5484edee..8f9bb5a6fc 100644 --- a/src/runtime/hashmap_fast.go +++ b/src/runtime/hashmap_fast.go @@ -5,7 +5,6 @@ package runtime import ( - "runtime/internal/atomic" "runtime/internal/sys" "unsafe" ) @@ -16,7 +15,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32)) } if h == nil || h.count == 0 { - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } if h.flags&hashWriting != 0 { throw("concurrent map read and map write") @@ -50,7 +49,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { } b = b.overflow(t) if b == nil { - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } } } @@ -61,7 +60,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast32)) } if h == nil || h.count == 0 { - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } if h.flags&hashWriting != 0 { throw("concurrent map read and map write") @@ -95,7 +94,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { } b = b.overflow(t) if b == nil { - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } } } @@ -106,7 +105,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast64)) } if h == nil || h.count == 0 { - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } if h.flags&hashWriting != 0 { throw("concurrent map read and map write") @@ -140,7 +139,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { } b = b.overflow(t) if b == nil { - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } } } @@ -151,7 +150,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast64)) } if h == nil || h.count == 0 { - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } if h.flags&hashWriting != 0 { throw("concurrent map read and map write") @@ -185,7 +184,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { } b = b.overflow(t) if b == nil { - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } } } @@ -196,7 +195,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_faststr)) } if h == nil || h.count == 0 { - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } if h.flags&hashWriting != 0 { throw("concurrent map read and map write") @@ -220,7 +219,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)) } } - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } // long key, try not to do more comparisons than necessary keymaybe := uintptr(bucketCnt) @@ -258,7 +257,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)) } } - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } dohash: hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0)) @@ -290,7 +289,7 @@ dohash: } b = b.overflow(t) if b == nil { - return atomic.Loadp(unsafe.Pointer(&zeroptr)) + return unsafe.Pointer(&zeroVal[0]) } } } @@ -301,7 +300,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr)) } if h == nil || h.count == 0 { - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } if h.flags&hashWriting != 0 { throw("concurrent map read and map write") @@ -325,7 +324,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true } } - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } // long key, try not to do more comparisons than necessary keymaybe := uintptr(bucketCnt) @@ -361,7 +360,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)), true } } - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } dohash: hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0)) @@ -393,7 +392,7 @@ dohash: } b = b.overflow(t) if b == nil { - return atomic.Loadp(unsafe.Pointer(&zeroptr)), false + return unsafe.Pointer(&zeroVal[0]), false } } } diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index 9d2894cb6f..496f8e8868 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -317,6 +317,22 @@ func TestBigItems(t *testing.T) { } } +func TestMapHugeZero(t *testing.T) { + type T [4000]byte + m := map[int]T{} + x := m[0] + if x != (T{}) { + t.Errorf("map value not zero") + } + y, ok := m[0] + if ok { + t.Errorf("map value should be missing") + } + if y != (T{}) { + t.Errorf("map value not zero") + } +} + type empty struct { } -- cgit v1.3 From 7e460e70d90295cf08ea627c0a0fff170aba5518 Mon Sep 17 00:00:00 2001 From: Martin Möhrmann Date: Wed, 20 Apr 2016 18:00:52 +0200 Subject: runtime: use type int to specify size for newarray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistently use type int for the size argument of runtime.newarray, runtime.reflect_unsafe_NewArray and reflect.unsafe_NewArray. Change-Id: Ic77bf2dde216c92ca8c49462f8eedc0385b6314e Reviewed-on: https://go-review.googlesource.com/22311 Reviewed-by: Keith Randall Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot --- src/runtime/chan.go | 2 +- src/runtime/hashmap.go | 4 ++-- src/runtime/malloc.go | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/runtime/hashmap.go') diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 3fb0236785..712ad8cef9 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -84,7 +84,7 @@ func makechan(t *chantype, size int64) *hchan { } } else { c = new(hchan) - c.buf = newarray(elem, uintptr(size)) + c.buf = newarray(elem, int(size)) } c.elemsize = uint16(elem.size) c.elemtype = elem diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index ff59faab5d..509cab2f0f 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -246,7 +246,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { // If hint is large zeroing this memory could take a while. buckets := bucket if B != 0 { - buckets = newarray(t.bucket, uintptr(1)< maxSliceCap(typ.size) { +// newarray allocates an array of n elements of type typ. +func newarray(typ *_type, n int) unsafe.Pointer { + if n < 0 || uintptr(n) > maxSliceCap(typ.size) { panic(plainError("runtime: allocation size out of range")) } - return mallocgc(typ.size*n, typ, true) + return mallocgc(typ.size*uintptr(n), typ, true) } //go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray -func reflect_unsafe_NewArray(typ *_type, n uintptr) unsafe.Pointer { +func reflect_unsafe_NewArray(typ *_type, n int) unsafe.Pointer { return newarray(typ, n) } -- cgit v1.3