// gathered here.
if n.Esc != EscHeap && n.Type != nil &&
(n.Type.Width > maxStackVarSize ||
- (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
+ (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize ||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
-
// isSmallMakeSlice returns false for non-constant len/cap.
// If that's the case, print a more accurate escape reason.
var msgVerb, escapeMsg string
)
const (
- BADWIDTH = types.BADWIDTH
+ BADWIDTH = types.BADWIDTH
+
+ // maximum size variable which we will allocate on the stack.
+ // This limit is for explicit variable declarations like "var x T" or "x := ...".
maxStackVarSize = 10 * 1024 * 1024
+
+ // maximum size of implicit variables that we will allocate on the stack.
+ // p := new(T) allocating T on the stack
+ // p := &T{} allocating T on the stack
+ // s := make([]T, n) allocating [n]T on the stack
+ // s := []byte("...") allocating [n]byte on the stack
+ maxImplicitStackVarSize = 64 * 1024
)
// isRuntimePkg reports whether p is package runtime.
}
t := n.Type
- return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
+ return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width)
}
// walk the whole tree of the body of an
case ONEW:
if n.Esc == EscNone {
- if n.Type.Elem().Width >= 1<<16 {
+ if n.Type.Elem().Width >= maxImplicitStackVarSize {
Fatalf("large ONEW with EscNone: %v", n)
}
r := temp(n.Type.Elem())
n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
- // stringtoslicebyte(*32[byte], string) []byte;
case OSTRARRAYBYTE:
+ s := n.Left
+ if Isconst(s, CTSTR) {
+ sc := s.Val().U.(string)
+
+ // Allocate a [n]byte of the right size.
+ t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
+ var a *Node
+ if n.Esc == EscNone && len(sc) <= maxImplicitStackVarSize {
+ a = nod(OADDR, temp(t), nil)
+ } else {
+ a = callnew(t)
+ }
+ p := temp(t.PtrTo()) // *[n]byte
+ init.Append(typecheck(nod(OAS, p, a), Etop))
+
+ // Copy from the static string data to the [n]byte.
+ if len(sc) > 0 {
+ as := nod(OAS,
+ nod(OIND, p, nil),
+ nod(OIND, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil))
+ init.Append(typecheck(as, Etop))
+ }
+
+ // Slice the [n]byte to a []byte.
+ n.Op = OSLICEARR
+ n.Left = p
+ n = walkexpr(n, init)
+ break
+ }
a := nodnil()
if n.Esc == EscNone {
a = nod(OADDR, temp(t), nil)
}
- n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, types.Types[TSTRING]))
+ // stringtoslicebyte(*32[byte], string) []byte;
+ n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[TSTRING]))
case OSTRARRAYBYTETMP:
// []byte(string) conversion that creates a slice
// Decomposing StringMake and lowering of StringPtr and StringLen
// happens in a later pass, dec, so that these operations are available
// to other passes for optimizations.
-(StringPtr (StringMake (Const64 <t> [c]) _)) -> (Const64 <t> [c])
+(StringPtr (StringMake (Addr <t> {s} base) _)) -> (Addr <t> {s} base)
(StringLen (StringMake _ (Const64 <t> [c]))) -> (Const64 <t> [c])
(ConstString {s}) && config.PtrSize == 4 && s.(string) == "" ->
(StringMake (ConstNil) (Const32 <typ.Int> [0]))
return false
}
func rewriteValuegeneric_OpStringPtr_0(v *Value) bool {
- // match: (StringPtr (StringMake (Const64 <t> [c]) _))
+ // match: (StringPtr (StringMake (Addr <t> {s} base) _))
// cond:
- // result: (Const64 <t> [c])
+ // result: (Addr <t> {s} base)
for {
v_0 := v.Args[0]
if v_0.Op != OpStringMake {
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpConst64 {
+ if v_0_0.Op != OpAddr {
break
}
t := v_0_0.Type
- c := v_0_0.AuxInt
- v.reset(OpConst64)
+ s := v_0_0.Aux
+ base := v_0_0.Args[0]
+ v.reset(OpAddr)
v.Type = t
- v.AuxInt = c
+ v.Aux = s
+ v.AddArg(base)
return true
}
return false
// amd64:`.*countrunes`
return len([]rune(s))
}
+
+func ToByteSlice() []byte { // Issue #24698
+ // amd64:`LEAQ\ttype\.\[3\]uint8`
+ // amd64:`CALL\truntime\.newobject`
+ // amd64:-`.*runtime.stringtoslicebyte`
+ return []byte("foo")
+}