summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/slice.goc
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/slice.goc')
-rw-r--r--src/pkg/runtime/slice.goc204
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);
+}