}
}
+func BenchmarkAppendGrowByte(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x []byte
+ for j := 0; j < 1<<20; j++ {
+ x = append(x, byte(j))
+ }
+ }
+}
+
+func BenchmarkAppendGrowString(b *testing.B) {
+ var s string
+ for i := 0; i < b.N; i++ {
+ var x []string
+ for j := 0; j < 1<<20; j++ {
+ x = append(x, s)
+ }
+ }
+}
+
func benchmarkAppendBytes(b *testing.B, length int) {
b.StopTimer()
x := make([]byte, 0, N)
// making new objects in class i
int32 runtime·SizeToClass(int32);
+uintptr runtime·roundupsize(uintptr);
extern int32 runtime·class_to_size[NumSizeClasses];
extern int32 runtime·class_to_allocnpages[NumSizeClasses];
extern int8 runtime·size_to_class8[1024/8 + 1];
}
runtime·throw("InitSizes failed");
}
+
+// Returns size of the memory block that mallocgc will allocate if you ask for the size.
+uintptr
+runtime·roundupsize(uintptr size)
+{
+ if(size < MaxSmallSize) {
+ if(size <= 1024-8)
+ return runtime·class_to_size[runtime·size_to_class8[(size+7)>>3]];
+ else
+ return runtime·class_to_size[runtime·size_to_class128[(size-1024+127) >> 7]];
+ }
+ if(size + PageSize < size)
+ return size;
+ return ROUND(size, PageSize);
+}
#include "typekind.h"
#include "malloc.h"
#include "race.h"
+#include "stack.h"
#include "../../cmd/ld/textflag.h"
enum
static void
growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret)
{
- intgo m;
+ intgo newcap1;
+ uintptr capmem, lenmem;
+ int32 flag;
+ Type *typ;
+
+ typ = t->elem;
+ if(typ->size == 0) {
+ *ret = x;
+ ret->cap = newcap;
+ return;
+ }
- m = x.cap;
+ 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(m+m < newcap)
- m = newcap;
+ if(newcap1+newcap1 < newcap)
+ newcap1 = newcap;
else {
do {
if(x.len < 1024)
- m += m;
+ newcap1 += newcap1;
else
- m += m/4;
- } while(m < newcap);
+ newcap1 += newcap1/4;
+ } while(newcap1 < newcap);
}
- makeslice1(t, x.len, m, ret);
- runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
+
+ if(newcap1 > MaxMem/typ->size)
+ runtime·panicstring("growslice: cap out of range");
+ capmem = runtime·roundupsize(newcap1*typ->size);
+ flag = FlagNoZero;
+ if(typ->kind&KindNoPointers)
+ flag |= FlagNoScan;
+ // Here we allocate with FlagNoZero but potentially w/o FlagNoScan,
+ // GC must not see this blocks until memclr below.
+ m->locks++;
+ 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);
+ runtime·memclr(ret->array+lenmem, capmem-lenmem);
+ m->locks--;
+ if(m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
+ g->stackguard0 = StackPreempt;
}
// copy(to any, fr any, wid uintptr) int
return s;
}
+// used by cmd/cgo
Slice
runtime·gobytes(byte *p, intgo n)
{
}
func stringtoslicebyte(s String) (b Slice) {
- b.array = runtime·mallocgc(s.len, 0, FlagNoScan|FlagNoZero);
+ uintptr cap;
+
+ cap = runtime·roundupsize(s.len);
+ b.array = runtime·mallocgc(cap, 0, FlagNoScan|FlagNoZero);
b.len = s.len;
- b.cap = s.len;
+ b.cap = cap;
runtime·memmove(b.array, s.str, s.len);
+ if(cap != b.len)
+ runtime·memclr(b.array+b.len, cap-b.len);
}
func slicerunetostring(b Slice) (s String) {
intgo n;
int32 dum, *r;
uint8 *p, *ep;
+ uintptr mem;
// two passes.
// unlike slicerunetostring, no race because strings are immutable.
n++;
}
- b.array = runtime·mallocgc(n*sizeof(r[0]), 0, FlagNoScan|FlagNoZero);
+ mem = runtime·roundupsize(n*sizeof(r[0]));
+ b.array = runtime·mallocgc(mem, 0, FlagNoScan|FlagNoZero);
b.len = n;
- b.cap = n;
+ b.cap = mem/sizeof(r[0]);
p = s.str;
r = (int32*)b.array;
while(p < ep)
p += runtime·charntorune(r++, p, ep-p);
+ if(b.cap > b.len)
+ runtime·memclr(b.array+b.len*sizeof(r[0]), (b.cap-b.len)*sizeof(r[0]));
}
enum