diff options
Diffstat (limited to 'src/pkg/runtime/slice.goc')
-rw-r--r-- | src/pkg/runtime/slice.goc | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/pkg/runtime/slice.goc b/src/pkg/runtime/slice.goc new file mode 100644 index 000000000..2a14dafab --- /dev/null +++ b/src/pkg/runtime/slice.goc @@ -0,0 +1,204 @@ +// 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 runtime +#include "runtime.h" +#include "arch_GOARCH.h" +#include "type.h" +#include "typekind.h" +#include "malloc.h" +#include "race.h" +#include "stack.h" +#include "../../cmd/ld/textflag.h" + +enum +{ + debug = 0 +}; + +static void makeslice1(SliceType*, intgo, intgo, Slice*); +static void growslice1(SliceType*, Slice, intgo, Slice *); + +// see also unsafe·NewArray +func makeslice(t *SliceType, len int64, cap int64) (ret Slice) { + // NOTE: The len > MaxMem/elemsize check here is not strictly necessary, + // but it produces a 'len out of range' error instead of a 'cap out of range' error + // when someone does make([]T, bignumber). 'cap out of range' is true too, + // but since the cap is only being supplied implicitly, saying len is clearer. + // See issue 4085. + if(len < 0 || (intgo)len != len || t->elem->size > 0 && len > MaxMem / t->elem->size) + runtime·panicstring("makeslice: len out of range"); + + if(cap < len || (intgo)cap != cap || t->elem->size > 0 && cap > MaxMem / t->elem->size) + runtime·panicstring("makeslice: cap out of range"); + + makeslice1(t, len, cap, &ret); + + if(debug) { + runtime·printf("makeslice(%S, %D, %D); ret=", + *t->string, len, cap); + runtime·printslice(ret); + } +} + +// Dummy word to use as base pointer for make([]T, 0). +// Since you cannot take the address of such a slice, +// you can't tell that they all have the same base pointer. +uintptr runtime·zerobase; + +static void +makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret) +{ + ret->len = len; + ret->cap = cap; + ret->array = runtime·cnewarray(t->elem, cap); +} + +// growslice(type *Type, x, []T, n int64) []T +func growslice(t *SliceType, old Slice, n int64) (ret Slice) { + int64 cap; + void *pc; + + if(n < 1) + runtime·panicstring("growslice: invalid n"); + + cap = old.cap + n; + + if((intgo)cap != cap || cap < (int64)old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size)) + runtime·panicstring("growslice: cap out of range"); + + if(raceenabled) { + pc = runtime·getcallerpc(&t); + runtime·racereadrangepc(old.array, old.len*t->elem->size, pc, runtime·growslice); + } + + growslice1(t, old, cap, &ret); + + if(debug) { + runtime·printf("growslice(%S,", *t->string); + runtime·printslice(old); + runtime·printf(", new cap=%D) =", cap); + runtime·printslice(ret); + } +} + +static void +growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret) +{ + intgo newcap1; + uintptr capmem, lenmem; + int32 flag; + Type *typ; + + typ = t->elem; + if(typ->size == 0) { + *ret = x; + ret->cap = newcap; + return; + } + + newcap1 = x.cap; + + // Using newcap directly for m+m < newcap handles + // both the case where m == 0 and also the case where + // m+m/4 wraps around, in which case the loop + // below might never terminate. + if(newcap1+newcap1 < newcap) + newcap1 = newcap; + else { + do { + if(x.len < 1024) + newcap1 += newcap1; + else + newcap1 += newcap1/4; + } while(newcap1 < newcap); + } + + if(newcap1 > MaxMem/typ->size) + runtime·panicstring("growslice: cap out of range"); + capmem = runtime·roundupsize(newcap1*typ->size); + flag = 0; + // Can't use FlagNoZero w/o FlagNoScan, because otherwise GC can scan unitialized memory. + if(typ->kind&KindNoPointers) + flag = FlagNoScan|FlagNoZero; + ret->array = runtime·mallocgc(capmem, (uintptr)typ|TypeInfo_Array, flag); + ret->len = x.len; + ret->cap = capmem/typ->size; + lenmem = x.len*typ->size; + runtime·memmove(ret->array, x.array, lenmem); + if(typ->kind&KindNoPointers) + runtime·memclr(ret->array+lenmem, capmem-lenmem); +} + +#pragma textflag NOSPLIT +func copy(to Slice, fm Slice, width uintptr) (ret int) { + void *pc; + + if(fm.len == 0 || to.len == 0 || width == 0) { + ret = 0; + goto out; + } + + ret = fm.len; + if(to.len < ret) + ret = to.len; + + if(raceenabled) { + pc = runtime·getcallerpc(&to); + runtime·racewriterangepc(to.array, ret*width, pc, runtime·copy); + runtime·racereadrangepc(fm.array, ret*width, pc, runtime·copy); + } + + if(ret == 1 && width == 1) { // common case worth about 2x to do here + *to.array = *fm.array; // known to be a byte pointer + } else { + runtime·memmove(to.array, fm.array, ret*width); + } + +out: + + if(debug) { + runtime·prints("main·copy: to="); + runtime·printslice(to); + runtime·prints("; fm="); + runtime·printslice(fm); + runtime·prints("; width="); + runtime·printint(width); + runtime·prints("; ret="); + runtime·printint(ret); + runtime·prints("\n"); + } +} + +#pragma textflag NOSPLIT +func slicestringcopy(to Slice, fm String) (ret int) { + void *pc; + + if(fm.len == 0 || to.len == 0) { + ret = 0; + goto out; + } + + ret = fm.len; + if(to.len < ret) + ret = to.len; + + if(raceenabled) { + pc = runtime·getcallerpc(&to); + runtime·racewriterangepc(to.array, ret, pc, runtime·slicestringcopy); + } + + runtime·memmove(to.array, fm.str, ret); + +out:; +} + +func printslice(a Slice) { + runtime·prints("["); + runtime·printint(a.len); + runtime·prints("/"); + runtime·printint(a.cap); + runtime·prints("]"); + runtime·printpointer(a.array); +} |