diff options
Diffstat (limited to 'libgo/go/runtime/slice.go')
-rw-r--r-- | libgo/go/runtime/slice.go | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go index b61c2b1..97b2659 100644 --- a/libgo/go/runtime/slice.go +++ b/libgo/go/runtime/slice.go @@ -41,6 +41,55 @@ func panicmakeslicecap() { panic(errorString("makeslice: cap out of range")) } +// makeslicecopy allocates a slice of "tolen" elements of type "et", +// then copies "fromlen" elements of type "et" into that new allocation from "from". +func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer { + var tomem, copymem uintptr + if uintptr(tolen) > uintptr(fromlen) { + var overflow bool + tomem, overflow = math.MulUintptr(et.size, uintptr(tolen)) + if overflow || tomem > maxAlloc || tolen < 0 { + panicmakeslicelen() + } + copymem = et.size * uintptr(fromlen) + } else { + // fromlen is a known good length providing and equal or greater than tolen, + // thereby making tolen a good slice length too as from and to slices have the + // same element width. + tomem = et.size * uintptr(tolen) + copymem = tomem + } + + var to unsafe.Pointer + if et.ptrdata == 0 { + to = mallocgc(tomem, nil, false) + if copymem < tomem { + memclrNoHeapPointers(add(to, copymem), tomem-copymem) + } + } else { + // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. + to = mallocgc(tomem, et, true) + if copymem > 0 && writeBarrier.enabled { + // Only shade the pointers in old.array since we know the destination slice to + // only contains nil pointers because it has been cleared during alloc. + bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem) + } + } + + if raceenabled { + callerpc := getcallerpc() + pc := funcPC(makeslicecopy) + racereadrangepc(from, copymem, callerpc, pc) + } + if msanenabled { + msanread(from, copymem) + } + + memmove(to, from, copymem) + + return to +} + 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 { @@ -187,7 +236,7 @@ func growslice(et *_type, oldarray unsafe.Pointer, oldlen, oldcap, cap int) slic if lenmem > 0 && writeBarrier.enabled { // Only shade the pointers in old.array since we know the destination slice p // only contains nil pointers because it has been cleared during alloc. - bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(oldarray), lenmem) + bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(oldarray), lenmem-et.size+et.ptrdata) } } memmove(p, oldarray, lenmem) @@ -199,14 +248,14 @@ func isPowerOfTwo(x uintptr) bool { return x&(x-1) == 0 } -func slicecopy(to, fm slice, width uintptr) int { - if fm.len == 0 || to.len == 0 { +func slicecopy(toPtr unsafe.Pointer, toLen int, fmPtr unsafe.Pointer, fmLen int, width uintptr) int { + if fmLen == 0 || toLen == 0 { return 0 } - n := fm.len - if to.len < n { - n = to.len + n := fmLen + if toLen < n { + n = toLen } if width == 0 { @@ -216,43 +265,43 @@ func slicecopy(to, fm slice, width uintptr) int { if raceenabled { callerpc := getcallerpc() pc := funcPC(slicecopy) - racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) - racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) + racereadrangepc(fmPtr, uintptr(n*int(width)), callerpc, pc) + racewriterangepc(toPtr, uintptr(n*int(width)), callerpc, pc) } if msanenabled { - msanwrite(to.array, uintptr(n*int(width))) - msanread(fm.array, uintptr(n*int(width))) + msanread(fmPtr, uintptr(n*int(width))) + msanwrite(toPtr, uintptr(n*int(width))) } size := uintptr(n) * width if size == 1 { // common case worth about 2x to do here // TODO: is this still worth it with new memmove impl? - *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer + *(*byte)(toPtr) = *(*byte)(fmPtr) // known to be a byte pointer } else { - memmove(to.array, fm.array, size) + memmove(toPtr, fmPtr, size) } return n } -func slicestringcopy(to []byte, fm string) int { - if len(fm) == 0 || len(to) == 0 { +func slicestringcopy(toPtr *byte, toLen int, fm string) int { + if len(fm) == 0 || toLen == 0 { return 0 } n := len(fm) - if len(to) < n { - n = len(to) + if toLen < n { + n = toLen } if raceenabled { callerpc := getcallerpc() pc := funcPC(slicestringcopy) - racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) + racewriterangepc(unsafe.Pointer(toPtr), uintptr(n), callerpc, pc) } if msanenabled { - msanwrite(unsafe.Pointer(&to[0]), uintptr(n)) + msanwrite(unsafe.Pointer(toPtr), uintptr(n)) } - memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n)) + memmove(unsafe.Pointer(toPtr), stringStructOf(&fm).str, uintptr(n)) return n } |