reflect: make more Value methods inlineable

The following Value methods are now inlineable:

    Bool  for ~bool
    String for ~string (but not other kinds)
    Bytes for []byte (but not ~[]byte or ~[N]byte)
    Len   for ~[]T (but not ~[N]T, ~chan T, ~map[K]V, or ~string)
    Cap   for ~[]T (but not ~[N]T or ~chan T)

For Bytes, we only have enough inline budget to inline one type,
so we optimize for unnamed []byte, which is far more common than
named []byte or [N]byte.

For Len and Cap, we only have enough inline budget to inline one kind,
so we optimize for ~[]T, which is more common than the others.
The exception is string, but the size of a string can be obtained
through len(v.String()).

Performance:

	Bool        1.65ns ± 0%  0.51ns ± 3%  -68.81%  (p=0.008 n=5+5)
	String      1.97ns ± 1%  0.70ns ± 1%  -64.25%  (p=0.008 n=5+5)
	Bytes       8.90ns ± 2%  0.89ns ± 1%  -89.95%  (p=0.008 n=5+5)
	NamedBytes  8.89ns ± 1%  8.88ns ± 1%     ~     (p=0.548 n=5+5)
	BytesArray  10.0ns ± 2%  10.2ns ± 1%   +1.58%  (p=0.048 n=5+5)
	SliceLen    1.97ns ± 1%  0.45ns ± 1%  -77.22%  (p=0.008 n=5+5)
	MapLen      2.62ns ± 1%  3.07ns ± 1%  +17.24%  (p=0.008 n=5+5)
	StringLen   1.96ns ± 1%  1.98ns ± 2%     ~     (p=0.151 n=5+5)
	ArrayLen    1.96ns ± 1%  2.19ns ± 1%  +11.46%  (p=0.008 n=5+5)
	SliceCap    1.76ns ± 1%  0.45ns ± 2%  -74.28%  (p=0.008 n=5+5)

There's a slight slowdown (~10-20%) for obtaining the length
of a string or map, but a substantial improvement for slices.

Performance according to encoding/json:

	CodeMarshal          555µs ± 2%   562µs ± 4%     ~     (p=0.421 n=5+5)
	MarshalBytes/32      163ns ± 1%   157ns ± 1%   -3.82%  (p=0.008 n=5+5)
	MarshalBytes/256     453ns ± 1%   447ns ± 1%     ~     (p=0.056 n=5+5)
	MarshalBytes/4096   4.10µs ± 1%  4.09µs ± 0%     ~     (p=1.000 n=5+4)
	CodeUnmarshal       3.16ms ± 2%  3.02ms ± 1%   -4.18%  (p=0.008 n=5+5)
	CodeUnmarshalReuse  2.64ms ± 3%  2.51ms ± 2%   -4.81%  (p=0.016 n=5+5)
	UnmarshalString     65.4ns ± 4%  64.1ns ± 0%     ~     (p=0.190 n=5+4)
	UnmarshalFloat64    59.8ns ± 5%  58.9ns ± 2%     ~     (p=0.222 n=5+5)
	UnmarshalInt64      51.7ns ± 1%  50.0ns ± 2%   -3.26%  (p=0.008 n=5+5)
	EncodeMarshaler     23.6ns ±11%  20.8ns ± 1%  -12.10%  (p=0.016 n=5+4)

Add all inlineable methods of Value to cmd/compile/internal/test/inl_test.go.

Change-Id: Ifc192491918af6b62f7fe3a094a5a5256bfb326d
Reviewed-on: https://go-review.googlesource.com/c/go/+/400676
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go
index 211068e..af66a32 100644
--- a/src/cmd/compile/internal/test/inl_test.go
+++ b/src/cmd/compile/internal/test/inl_test.go
@@ -128,15 +128,33 @@
 			"ValidRune",
 		},
 		"reflect": {
-			"Value.CanInt",
-			"Value.CanUint",
-			"Value.CanFloat",
-			"Value.CanComplex",
+			"Value.Bool",
+			"Value.Bytes",
 			"Value.CanAddr",
-			"Value.CanSet",
+			"Value.CanComplex",
+			"Value.CanFloat",
+			"Value.CanInt",
 			"Value.CanInterface",
+			"Value.CanSet",
+			"Value.CanUint",
+			"Value.Cap",
+			"Value.Complex",
+			"Value.Float",
+			"Value.Int",
+			"Value.Interface",
+			"Value.IsNil",
 			"Value.IsValid",
+			"Value.Kind",
+			"Value.Len",
 			"Value.MapRange",
+			"Value.OverflowComplex",
+			"Value.OverflowFloat",
+			"Value.OverflowInt",
+			"Value.OverflowUint",
+			"Value.String",
+			"Value.Type",
+			"Value.Uint",
+			"Value.UnsafeAddr",
 			"Value.pointer",
 			"add",
 			"align",
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index a886f9f..72d01c7 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -7823,3 +7823,93 @@
 		t.Fatalf("Kind(-1).String() = %q, want %q", s, want)
 	}
 }
+
+type (
+	namedBool  bool
+	namedBytes []byte
+)
+
+var sourceAll = struct {
+	Bool         Value
+	String       Value
+	Bytes        Value
+	NamedBytes   Value
+	BytesArray   Value
+	SliceAny     Value
+	MapStringAny Value
+}{
+	Bool:         ValueOf(new(bool)).Elem(),
+	String:       ValueOf(new(string)).Elem(),
+	Bytes:        ValueOf(new([]byte)).Elem(),
+	NamedBytes:   ValueOf(new(namedBytes)).Elem(),
+	BytesArray:   ValueOf(new([32]byte)).Elem(),
+	SliceAny:     ValueOf(new([]any)).Elem(),
+	MapStringAny: ValueOf(new(map[string]any)).Elem(),
+}
+
+var sinkAll struct {
+	RawBool   bool
+	RawString string
+	RawBytes  []byte
+	RawInt    int
+}
+
+func BenchmarkBool(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawBool = sourceAll.Bool.Bool()
+	}
+}
+
+func BenchmarkString(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawString = sourceAll.String.String()
+	}
+}
+
+func BenchmarkBytes(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawBytes = sourceAll.Bytes.Bytes()
+	}
+}
+
+func BenchmarkNamedBytes(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawBytes = sourceAll.NamedBytes.Bytes()
+	}
+}
+
+func BenchmarkBytesArray(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawBytes = sourceAll.BytesArray.Bytes()
+	}
+}
+
+func BenchmarkSliceLen(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawInt = sourceAll.SliceAny.Len()
+	}
+}
+
+func BenchmarkMapLen(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawInt = sourceAll.MapStringAny.Len()
+	}
+}
+
+func BenchmarkStringLen(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawInt = sourceAll.String.Len()
+	}
+}
+
+func BenchmarkArrayLen(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawInt = sourceAll.BytesArray.Len()
+	}
+}
+
+func BenchmarkSliceCap(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		sinkAll.RawInt = sourceAll.SliceAny.Cap()
+	}
+}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index de24d4c..6b5ebfa 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -281,14 +281,31 @@
 // Bool returns v's underlying value.
 // It panics if v's kind is not Bool.
 func (v Value) Bool() bool {
-	v.mustBe(Bool)
+	// panicNotBool is split out to keep Bool inlineable.
+	if v.kind() != Bool {
+		v.panicNotBool()
+	}
 	return *(*bool)(v.ptr)
 }
 
+func (v Value) panicNotBool() {
+	v.mustBe(Bool)
+}
+
+var bytesType = TypeOf(([]byte)(nil)).(*rtype)
+
 // Bytes returns v's underlying value.
 // It panics if v's underlying value is not a slice of bytes or
 // an addressable array of bytes.
 func (v Value) Bytes() []byte {
+	// bytesSlow is split out to keep Bytes inlineable for unnamed []byte.
+	if v.typ == bytesType {
+		return *(*[]byte)(v.ptr)
+	}
+	return v.bytesSlow()
+}
+
+func (v Value) bytesSlow() []byte {
 	switch v.kind() {
 	case Slice:
 		if v.typ.Elem().Kind() != Uint8 {
@@ -1129,15 +1146,20 @@
 // Cap returns v's capacity.
 // It panics if v's Kind is not Array, Chan, or Slice.
 func (v Value) Cap() int {
+	// capNonSlice is split out to keep Cap inlineable for slice kinds.
+	if v.kind() == Slice {
+		return (*unsafeheader.Slice)(v.ptr).Cap
+	}
+	return v.capNonSlice()
+}
+
+func (v Value) capNonSlice() int {
 	k := v.kind()
 	switch k {
 	case Array:
 		return v.typ.Len()
 	case Chan:
 		return chancap(v.pointer())
-	case Slice:
-		// Slice is always bigger than a word; assume flagIndir.
-		return (*unsafeheader.Slice)(v.ptr).Cap
 	}
 	panic(&ValueError{"reflect.Value.Cap", v.kind()})
 }
@@ -1580,8 +1602,15 @@
 // Len returns v's length.
 // It panics if v's Kind is not Array, Chan, Map, Slice, or String.
 func (v Value) Len() int {
-	k := v.kind()
-	switch k {
+	// lenNonSlice is split out to keep Len inlineable for slice kinds.
+	if v.kind() == Slice {
+		return (*unsafeheader.Slice)(v.ptr).Len
+	}
+	return v.lenNonSlice()
+}
+
+func (v Value) lenNonSlice() int {
+	switch k := v.kind(); k {
 	case Array:
 		tt := (*arrayType)(unsafe.Pointer(v.typ))
 		return int(tt.len)
@@ -1589,9 +1618,6 @@
 		return chanlen(v.pointer())
 	case Map:
 		return maplen(v.pointer())
-	case Slice:
-		// Slice is bigger than a word; assume flagIndir.
-		return (*unsafeheader.Slice)(v.ptr).Len
 	case String:
 		// String is bigger than a word; assume flagIndir.
 		return (*unsafeheader.String)(v.ptr).Len
@@ -2441,12 +2467,17 @@
 // The fmt package treats Values specially. It does not call their String
 // method implicitly but instead prints the concrete values they hold.
 func (v Value) String() string {
-	switch k := v.kind(); k {
-	case Invalid:
-		return "<invalid Value>"
-	case String:
+	// stringNonString is split out to keep String inlineable for string kinds.
+	if v.kind() == String {
 		return *(*string)(v.ptr)
 	}
+	return v.stringNonString()
+}
+
+func (v Value) stringNonString() string {
+	if v.kind() == Invalid {
+		return "<invalid Value>"
+	}
 	// If you call String on a reflect.Value of other type, it's better to
 	// print something than to panic. Useful in debugging.
 	return "<" + v.Type().String() + " Value>"