internal/impl: improve MessageInfo.New performance

Calling the ProtoReflect method of the newly-constructed
message avoids an allocation in MessageInfo.MessageOf in
the common case of a generated message with an optimized
ProtoReflect method.

Benchmark for creating an empty message, darwin/arm64 M1 laptop:

    name                 old time/op    new time/op    delta
    EmptyMessage/New-10    32.1ns ± 2%    23.7ns ± 2%  -26.06%  (p=0.000 n=10+9)

    name                 old alloc/op   new alloc/op   delta
    EmptyMessage/New-10     64.0B ± 0%     48.0B ± 0%  -25.00%  (p=0.000 n=10+10)

    name                 old allocs/op  new allocs/op  delta
    EmptyMessage/New-10      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)

Change-Id: Ifa3c3ffa8edc76f78399306d0f4964eae4aacd28
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/418677
Reviewed-by: Michael Stapelberg <stapelberg@google.com>
Reviewed-by: Lasse Folger <lassefolger@google.com>
diff --git a/internal/benchmarks/micro/micro_test.go b/internal/benchmarks/micro/micro_test.go
index dd96744..cbfb244 100644
--- a/internal/benchmarks/micro/micro_test.go
+++ b/internal/benchmarks/micro/micro_test.go
@@ -67,6 +67,14 @@
 			}
 		})
 	})
+	b.Run("New", func(b *testing.B) {
+		mt := (&emptypb.Empty{}).ProtoReflect().Type()
+		b.RunParallel(func(pb *testing.PB) {
+			for pb.Next() {
+				mt.New()
+			}
+		})
+	})
 }
 
 // BenchmarkRepeatedInt32 tests a message containing 500 non-packed repeated int32s.
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 3945ab2..4f5fb67 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -218,7 +218,11 @@
 }
 
 func (mi *MessageInfo) New() protoreflect.Message {
-	return mi.MessageOf(reflect.New(mi.GoReflectType.Elem()).Interface())
+	m := reflect.New(mi.GoReflectType.Elem()).Interface()
+	if r, ok := m.(protoreflect.ProtoMessage); ok {
+		return r.ProtoReflect()
+	}
+	return mi.MessageOf(m)
 }
 func (mi *MessageInfo) Zero() protoreflect.Message {
 	return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())