// 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. #include "runtime.h" #include "arch_GOARCH.h" #include "type.h" #include "typekind.h" #include "malloc.h" #include "race.h" enum { debug = 0 }; static void makeslice1(SliceType*, intgo, intgo, Slice*); static void growslice1(SliceType*, Slice, intgo, Slice *); void runtime·copy(Slice to, Slice fm, uintptr width, intgo ret); // see also unsafe·NewArray // makeslice(typ *Type, len, cap int64) (ary []any); void runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret) { // 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); } // appendslice(type *Type, x, y, []T) []T #pragma textflag 7 void runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret) { intgo m; uintptr w; void *pc; uint8 *p, *q; m = x.len+y.len; w = t->elem->size; if(m < x.len) runtime·throw("append: slice overflow"); if(m > x.cap) growslice1(t, x, m, &ret); else ret = x; if(raceenabled) { // Don't mark read/writes on the newly allocated slice. pc = runtime·getcallerpc(&t); // read x[:len] if(m > x.cap) runtime·racereadrangepc(x.array, x.len*w, w, pc, runtime·appendslice); // read y runtime·racereadrangepc(y.array, y.len*w, w, pc, runtime·appendslice); // write x[len(x):len(x)+len(y)] if(m <= x.cap) runtime·racewriterangepc(ret.array+ret.len*w, y.len*w, w, pc, runtime·appendslice); } // A very common case is appending bytes. Small appends can avoid the overhead of memmove. // We can generalize a bit here, and just pick small-sized appends. p = ret.array+ret.len*w; q = y.array; w *= y.len; if(w <= appendCrossover) { if(p <= q || w <= p-q) // No overlap. while(w-- > 0) *p++ = *q++; else { p += w; q += w; while(w-- > 0) *--p = *--q; } } else { runtime·memmove(p, q, w); } ret.len += y.len; FLUSH(&ret); } // appendstr([]byte, string) []byte #pragma textflag 7 void runtime·appendstr(SliceType *t, Slice x, String y, Slice ret) { intgo m; void *pc; uintptr w; uint8 *p, *q; m = x.len+y.len; if(m < x.len) runtime·throw("append: string overflow"); if(m > x.cap) growslice1(t, x, m, &ret); else ret = x; if(raceenabled) { // Don't mark read/writes on the newly allocated slice. pc = runtime·getcallerpc(&t); // read x[:len] if(m > x.cap) runtime·racereadrangepc(x.array, x.len, 1, pc, runtime·appendstr); // write x[len(x):len(x)+len(y)] if(m <= x.cap) runtime·racewriterangepc(ret.array+ret.len, y.len, 1, pc, runtime·appendstr); } // Small appends can avoid the overhead of memmove. w = y.len; p = ret.array+ret.len; q = y.str; if(w <= appendCrossover) { while(w-- > 0) *p++ = *q++; } else { runtime·memmove(p, q, w); } ret.len += y.len; FLUSH(&ret); } // growslice(type *Type, x, []T, n int64) []T void runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) { int64 cap; void *pc; if(n < 1) runtime·panicstring("growslice: invalid n"); cap = old.cap + n; if((intgo)cap != cap || cap < 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, t->elem->size, pc, runtime·growslice); } growslice1(t, old, cap, &ret); FLUSH(&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 m; m = 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(m+m < newcap) m = newcap; else { do { if(x.len < 1024) m += m; else m += m/4; } while(m < newcap); } makeslice1(t, x.len, m, ret); runtime·memmove(ret->array, x.array, ret->len * t->elem->size); } // copy(to any, fr any, wid uintptr) int #pragma textflag 7 void runtime·copy(Slice to, Slice fm, uintptr width, intgo ret) { 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, width, pc, runtime·copy); runtime·racereadrangepc(fm.array, ret*width, 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: FLUSH(&ret); 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 7 void runtime·slicestringcopy(Slice to, String fm, intgo ret) { 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, 1, pc, runtime·slicestringcopy); } runtime·memmove(to.array, fm.str, ret); out: FLUSH(&ret); } void runtime·printslice(Slice a) { runtime·prints("["); runtime·printint(a.len); runtime·prints("/"); runtime·printint(a.cap); runtime·prints("]"); runtime·printpointer(a.array); }