// Using uint here means that if the computation of ntmp overflowed,
// we will call growslice which will panic.
- Expression* left = Expression::make_temporary_reference(ntmp, loc);
- left = Expression::make_cast(uint_type, left, loc);
-
Named_object* capfn = gogo->lookup_global("cap");
Expression* capref = Expression::make_func_reference(capfn, NULL, loc);
call_args = new Expression_list();
call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
- Expression* right = Expression::make_call(capref, call_args, false, loc);
+ Expression* cap = Expression::make_call(capref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &cap);
+ gogo->flatten_expression(function, inserter, &cap);
+ Temporary_statement* c1tmp = Statement::make_temporary(int_type, cap, loc);
+ inserter->insert(c1tmp);
+
+ Expression* left = Expression::make_temporary_reference(ntmp, loc);
+ left = Expression::make_cast(uint_type, left, loc);
+ Expression* right = Expression::make_temporary_reference(c1tmp, loc);
right = Expression::make_cast(uint_type, right, loc);
Expression* cond = Expression::make_binary(OPERATOR_GT, left, right, loc);
+ Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type());
Expression* a1 = Expression::make_type_descriptor(element_type, loc);
Expression* a2 = Expression::make_temporary_reference(s1tmp, loc);
- Expression* a3 = Expression::make_temporary_reference(ntmp, loc);
- Expression* call = Runtime::make_call(Runtime::GROWSLICE, loc, 3,
- a1, a2, a3);
+ a2 = slice_type->array_type()->get_value_pointer(gogo, a2, false);
+ a2 = Expression::make_cast(unsafe_ptr_type, a2, loc);
+ Expression* a3 = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* a4 = Expression::make_temporary_reference(c1tmp, loc);
+ Expression* a5 = Expression::make_temporary_reference(ntmp, loc);
+ Expression* call = Runtime::make_call(Runtime::GROWSLICE, loc, 5,
+ a1, a2, a3, a4, a5);
call = Expression::make_unsafe_cast(slice_type, call, loc);
ref = Expression::make_temporary_reference(s1tmp, loc);
// and it returns a new slice with at least that capacity, with the old data
// copied into it.
// The new slice's length is set to the requested capacity.
-func growslice(et *_type, old slice, cap int) slice {
+func growslice(et *_type, oldarray unsafe.Pointer, oldlen, oldcap, cap int) slice {
if raceenabled {
callerpc := getcallerpc()
- racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
+ racereadrangepc(oldarray, uintptr(oldlen*int(et.size)), callerpc, funcPC(growslice))
}
if msanenabled {
- msanread(old.array, uintptr(old.len*int(et.size)))
+ msanread(oldarray, uintptr(oldlen*int(et.size)))
}
- if cap < old.cap {
+ if cap < oldcap {
panic(errorString("growslice: cap out of range"))
}
if et.size == 0 {
// append should not create a slice with nil pointer but non-zero len.
- // We assume that append doesn't need to preserve old.array in this case.
+ // We assume that append doesn't need to preserve oldarray in this case.
return slice{unsafe.Pointer(&zerobase), cap, cap}
}
- newcap := old.cap
+ newcap := oldcap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
- if old.len < 1024 {
+ if oldlen < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// For powers of 2, use a variable shift.
switch {
case et.size == 1:
- lenmem = uintptr(old.len)
+ lenmem = uintptr(oldlen)
newlenmem = uintptr(cap)
capmem = roundupsize(uintptr(newcap))
overflow = uintptr(newcap) > maxAlloc
newcap = int(capmem)
case et.size == sys.PtrSize:
- lenmem = uintptr(old.len) * sys.PtrSize
+ lenmem = uintptr(oldlen) * sys.PtrSize
newlenmem = uintptr(cap) * sys.PtrSize
capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
} else {
shift = uintptr(sys.Ctz32(uint32(et.size))) & 31
}
- lenmem = uintptr(old.len) << shift
+ lenmem = uintptr(oldlen) << shift
newlenmem = uintptr(cap) << shift
capmem = roundupsize(uintptr(newcap) << shift)
overflow = uintptr(newcap) > (maxAlloc >> shift)
newcap = int(capmem >> shift)
default:
- lenmem = uintptr(old.len) * et.size
+ lenmem = uintptr(oldlen) * et.size
newlenmem = uintptr(cap) * et.size
capmem, overflow = math.MulUintptr(et.size, uintptr(newcap))
capmem = roundupsize(capmem)
var p unsafe.Pointer
if et.kind&kindNoPointers != 0 {
p = mallocgc(capmem, nil, false)
- // The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length).
+ // The append() that calls growslice is going to overwrite from oldlen to cap (which will be the new length).
// Only clear the part that will not be overwritten.
memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
} else {
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
p = mallocgc(capmem, et, true)
if writeBarrier.enabled {
- // Only shade the pointers in old.array since we know the destination slice p
+ // Only shade the pointers in oldarray since we know the destination slice p
// only contains nil pointers because it has been cleared during alloc.
- bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem)
+ bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(oldarray), lenmem)
}
}
- memmove(p, old.array, lenmem)
+ memmove(p, oldarray, lenmem)
return slice{p, cap, newcap}
}